There is this custom WCF REST service hosted inside a Sharepoint 2010 application using Windows Authentication.
I need to consume this service in a .NET project (i.e. console project) but the credential thing is driving me crazy. I'm getting lots of 400 - bad request
or 401 - unauthorized
responses (depending wether I include some authentication or not).
Let me give you an example:
siteUri
is the url of the SP site (the root/home page) and methodUri
is the url of the service method that returns an XML.
Again, this site is windows authenticated. If I open the browser and go to methodUri
I get:
Request Error
The server encountered an error processing the request. See server logs for more details.
But if then I go to siteUri
, the Sharepoint home page loads and then I can browse to methodUri
again and now I get the XML response correctly.
So it seems that browsing to the homepage stores some cookies that then are used when making the request to the web method. Checking the requests in Fiddler I can confirm this:
The first methodUri
request fails with 400
code and doesn't have any Cookies in the request header. Then when I browse the homepage (siteUri
) there are a few requests/responses that seems to be the authentication itself. The response header includes:
WWW-Authenticate: Negotiate oRswGaADCgEAoxIEEAEAAABDh+CIwTbjqQAAAAA=
Set-Cookie: WSS_KeepSessionAuthenticated={b89d78b2-063d-4ac4-810e-bde4e04a829e}; path=/
Persistent-Auth: true
And last, when browsing to methodUri
again first response is 401 - Unauthorized, but just after that there is another request including this headers
Cookie: WSS_KeepSessionAuthenticated={b89d78b2-063d-4ac4-810e-bde4e04a829e}
Authorization: Negotiate oXcwdaADCgEBoloEWE5UTE1TU1AAAwAAAAAAAABYAAAAAAAAAFgAAAAAAAAAWAAAAAAAAABYAAAAAAAAAFgAAAAAAAAAWAAAABXCiOIGAbEdAAAAD37/i76Dl3jNyK8bIRz57fmjEgQQAQAAAPUXp1AtIpqEAAAAAA==
that finally are accepted and the service responds with the corresponding XML.
So the browser is smart enough to handle this back and forth requests/responses to authenticate the current windows user.
My problem is, how can I do this in .NET (3.5 or 4) but WITHOUT using the defautl credentials, I need to specify the username, pwd and domain.
I've spent 5 days dealing with this and I could make it work using default network credentials in the HttpWebRequest, but when I set the credentials manually (using the same as the current logged in user) it doesn't work.
I just find this whole thing unnecesarily over-complicated (thank you Microsoft) because I come from an open source (ruby, python) background and this kind of things are just plain easy.
Hope I'm clear, if you need any extra information just ask. I'm willing to give my whole reputation in a bounty for this.
Thanks
Well, I've fixed it.
This is the code I've ended up using. Thanks to Microsoft for putting things so easy and well-explained.
var siteUri = @"http://sharepoint-site-uri";
var methodUri = @"http://sharepoint-site-uri/namespace/service/method";
string responseXml = null;
var request = (HttpWebRequest)WebRequest.Create(siteUri);
var cc = new CredentialCache { { new Uri(siteUri), "NTLM", new NetworkCredential("user", "pwd", "domain") } };
request.Credentials = cc;
try
{
// first site request
var response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
request = (HttpWebRequest)WebRequest.Create(uri);
request.CookieContainer = new CookieContainer();
// copy the authentication cookies from the response
foreach (Cookie c in response.Cookies)
{
request.CookieContainer.Add(c);
}
request.ContentType = "application/xml; charset=utf-8";
// second request, now against the service url
using (var reader = new StreamReader(request.GetResponse().GetResponseStream()))
{
// get the response text
responseXml = reader.ReadToEnd();
}
}
}
catch (Exception e)
{
// handle error
}