In one of my projects I had to read data from Exchange Server 2003 programmatically. I had access to Outlook Web Access that used Form Based Authentication (FBA). After some hacking and testing I got authentication part of my utility work. The point was easy – before making WebDAV requests to Exchange Server we need authentication cookies, so there is active session we can use.
At first let’s see namespaces I used in my code to get FBA stuff work.
using System.Text;
using System.Net;
using System.Security.Authentication;
using System.Web;
And here is the authentication method that returns session cookies if authentication succeeded. You can use these cookies if you have to execute WebDAV queries by example.
private CookieCollection DoExchangeFBA(string server, string userName, string password)
{
var uri = server + "/exchweb/bin/auth/owaauth.dll";
var request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = "POST";
request.CookieContainer = new CookieContainer();
request.ContentType = "application/x-www-form-urlencoded";
request.AllowAutoRedirect = false;
request.ServicePoint.Expect100Continue = false;
server = HttpUtility.UrlEncode(server);
userName = HttpUtility.UrlEncode(userName);
password = HttpUtility.UrlEncode(password);
var bodyString = "destination={0}&flags=0&username={1}";
bodyString += "&password={2}&SubmitCreds=Log+On&";
bodyString += "forcedownlevel=0&trusted=0";
bodyString = string.Format(bodyString, server,
userName, password);
var body = Encoding.ASCII.GetBytes(bodyString);
request.ContentLength = body.Length;
ServicePointManager.Expect100Continue = false;
var stream = request.GetRequestStream();
stream.Write(body, 0, body.Length);
stream.Close();
var response = (HttpWebResponse)request.GetResponse();
if (response.Cookies.Count < 2) throw
new AuthenticationException("Failed to login to OWA!");
return response.Cookies;
}
If you are using Exhange Server 2007 then you have different authentication address and you get back only one cookie.
View Comments (17)
Hi Gunnar,
Thanks for the post, I've tried your code (and some similar code I've written) but just get a 400 bad request back from the server when I try to make use of the cookieCollection:
Request.CookieContainer.Add(DoExchangeFBA("https://" + mailboxServer, "nwtraders\\dave hope", "Password"));
The raw http request looks like the following:
PROPFIND /exchange/owatest@nwtraders.msft/non_ipm_subtree/ HTTP/1.1
Host: exchange.nwtraders.msft
Cookie: sessionid=7a7c69df-0455-4g58-a96e-4e72388f4efa:000; cadata="1lsLZBvnfDk/Np9dfgFFtfgT91xl9UMjTsf7YxJ7IUufEVYQCm443d7qqxqvafmPKELKxT9yQFeG/2SFN0fTOAv6Q=="
Content-Length: 141
Expect: 100-continue
<?xml version="1.0"?><a:propfind xmlns:a="DAV:" xmlns:d="schemas.microsoft.com/exchange/"><a:prop><d:oof-state/></a:prop></a:propfind>
Any ideas as to where I'm going wrong?
Thanks,
Dave
I have seen this error in rather weird situation. I wrote command line application that imports calendars data from Exchange to SharePoint. Everything worked fine. I decided to create SharePoint server timer job based on this code. Without any markable modifications this code is not able to work under SharePoint timer process. After authentication it always gets error 400 bad request.
Can you tell me more about your technical environment? Maybe it is possible to find out what is going on
Thanks for the response!
We have multiple exchange servers. The code works fine against those which use Negotiate authentication but not those using FBA.
The code fails when making the request from the exchange servers itself. It's Exchange 2003 with all updates applied running on Windows 2k3 SP2 (again, with all updates applied).
Is there any specific information I can provide?
Thanks!
Dave
Problem solved! - I was doing two things wrong:
Not specifying the content-type in my request:
Request.ContentType = "text/xml";
The FBA login was redirecting, which I shouldn't have followed. Doing the following fixed it:
request.AllowAutoRedirect = false;
Thanks
Dave
Very good stuff! Do you have the same for exchange 2007
Best regards
Thor
Hello Thor!
Basically you can use this code also with Exchange 2007 but you have to make some little changes.
1. Exchange 2007 has different URL for authentication DLL.
2. There is only one authentication cookie for Exchange 2007
Hi,
This solution works fine.However we need to give "password" in this case. In a case when we are using default credentials, can it be done without password?
Hi Gunnar,
Thank you for posting this code. Are you able to offer me an example of how I might use your code to prevent the OWA login screen from appearing when a user clicks on a link to an inbox item? I am initially authenticating (successfully), passing a webDAV query, and returning & displaying the results on an .aspx (2.0) page. Within the results I have created anchor tags hyperlinked (using the exchange protocol format) to inbox items. However, when a user clicks on the item, the OWA login screen comes up. Specifically, how can I implement your code to bypass this screen?
Thank you,
Erik Snyder
If you want it to be done easily then use Windows authentication. Browser takes care of everything. Otherwise... try to put these session cookies to user's browser. See what happens.
Hi,
Thanks for posting the code. But when tring to get the cookies we are getting 401 Unauthorized error. Could please let me know what could be the reason in getting 401 Unauthorized error?
Thank You,
KVL
error in Exchange 2007:
details error:
The remote certificate is invalid according to the validation procedure.
I know this is a very old post. But I going to try my luck anyway for an answer. I wrote a authenticate function based on your code.
I am trying to connect to exchage 2007 , I keep getting bad request 400. I am not sure what i am doing wrong ,please help.
My url's work fine. and the username & password is right.
public void authenticate()
{
string authURI = server + "/owa/auth/owaauth.dll";
// Create the web request body:
string body = string.Format("destination={0}&username={1}&password={2}", server + path, username, password);
byte[] bytes = Encoding.UTF8.GetBytes(body);
// Create the web request:
HttpWebRequest request = (HttpWebRequest)System.Net.WebRequest.Create(authURI);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.CookieContainer = new CookieContainer();
request.ContentLength = bytes.Length;
request.UseDefaultCredentials = true;
// Create the web request content stream:
// request.KeepAlive = true;
//request.AllowAutoRedirect = true;
using (Stream stream = request.GetRequestStream())
{
stream.Write(bytes, 0, bytes.Length);
stream.Close();
}
// Get the response & store the authentication cookies:
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.Cookies.Count < 2)
{
Response.Write("Login Failed");
//throw new AuthenticationException("Login failed. Is the login / password correct?");
}
else
{
CookieContainer cookies = new CookieContainer();
foreach (Cookie myCookie in response.Cookies)
{
cookies.Add(myCookie);
}
}
response.Close();
}
Just a quick note to the above post i made ,
the destination path is of the form
http://exchange.myserver.com/.../myemail@address.com
I tested this url in ie and it works.
Just take fiddler2 and set it as proxy in your test machine. Now make all tasks you need to do in your code through OWA and save those requests and responses.
Now make your application work exactly same way. Use fiddler2 to monitor requests that your application makes. You should get all work done pretty quickly this way.
Can somebody put similar code for exchange 2010.
What is the url for authentication dll, is this url ("/owa/auth.owa") correct
Thanks for question, MadhuGowda! If you are lucky one with Exchange Server 2007 or 2010 you don't have to use WebDAV protocol to communicate with Exchange Server. You can use web services and this is preferred way over WebDAV.
Posting to the dll for owa no longer works in 2010, I have it working for 2007, does anyone know what they changed? I have been working on this for days with no resolve.