Imagine you have an OData Service installed on your domain somewhere, probably using the .NET Data Services producer libraries, and you want to authenticate clients against your corporate active directory.
How do you do this?
First on the IIS box hosting your Data Service you need to turn on integrated security, and you may want to turn off anonymous access too.
Now all unauthenticated requests to the website hosting your data service will be issued a HTTP 401 Challenge.
For Windows Authentication the 401 response will include these headers: WWW-Authenticate: NTLM WWW-Authenticate: Negotiate
The NTLM header means you need to use Windows Authentication. The Negotiate header means that the client can try to negotiate the use of Kerberos to authenticate. But that is only possible if both the client and server have access to a shared Kerberos Key Distribution Centre (KDC).
If, for whatever reason, a KDC isn’t available a standard NTML handshake will occur.
While we are looking into Windows Authentication it is worth quickly covering basic auth too because the process is very similar.
When you configure IIS to use Basic Auth the 401 will have a different header: WWW-Authenticate: Basic realm="mydomain.com"
This tells the client to do a Basic Auth handshake to provide credentials for 'mydomain.com'. The ‘handshake’ in Basic Auth is very simple – and very insecure – unless you are also using https.
Now that a NTLM challenge has been made, what happens next?
Most browsers will present a logon dialog when they receive a 401 challenge. So assuming the user provides valid credentials they are typically free to start browsing the rest of site and by extension the OData service.
Occasionally the browser and the website can "Negotiate" and agree to use kerberos, in which case the authentication can happen automatically without any user input.
The key takeaway though is that in a browser it is pretty easy to authenticate against a Data Service that is secured by Windows Authentication.
In a .NET client application using the standard .NET Data Services client – or for that matter the open source version – you need to tell data services your credentials.
Which you do like this:
MyDataContext ctx = new MyDataContext(uri); ctx.Credentials = System.Net.CredentialCache.DefaultCredentials; The example above makes sense if your client application is running under a windows account that has access to the server. If not however you will have to create a new set of NetworkCredentials and use them instead.
ctx.Credentials = new NetworkCredential( "username", "password", "domain");
As you can see, pretty simple.
Silverlight on the other hand is a little different.
If it is running in the browser – the only option in SL2 & 3 - then by default the Data Services client will re-use the cookies and authentication headers already established by the browser.
In fact in Silverlight 2 & 3 that is all it can do. The Silverlight client library doesn’t have a Credentials property so there is no way to use different credentials.
Typically if your SL app is hosted by a site that requires Windows Authentication, you don’t have a problem – because in order to download the Silverlight app, you need to authenticate in the browser first.
Which means from the perspective of the Data Service you are already authenticated.
Warning: While it is possible in Silverlight to do x-domain calls, so long as the other domain has a correctly configured ClientAccessPolicy.xml file, if the other domain needs you to logon, there is no way to provide your credentials.
Silverlight 4 is significantly more flexible, because it adds a Credentials property to the DataServiceContext. Which you can use to provide a different set of credentials if required.
In fact, if you think about it, because SL4 can run 'out of browser' the ability to set credentials directly is absolutely vital.
Despite this new feature in SL4 there are still some differences between .NET and SL4.
In SL4 there is no CredentialsCache so you can’t re-use the DefaultCredentials from the client. However we added a very handy property instead:
ctx.UseDefaultCredentials = true;
As you can see using Windows Authentication with OData is pretty simple, especially if you are using the Data Services libraries.
But even if you can’t, the principles are easy enough, so clients designed for other platforms should be able to authenticate without too much trouble too.
Next time out we’ll cover a more complicated scenario involving OAuth.
How we can achieve this when we use the open source odata library for Objective C.
(I wants to use a WCF data service from iPhone app)
You said in the part 2 you'll treat the FormsAuthentication - what happened to that?
how about JAVA? how do we authenticate over https?
typo there --> "If, for whatever reason, a KDC isn’t available a standard NTML handshake will occur."
NTLM not NTML
What about if the service is on a url in a asp.net mvc website (like nerddinner.com/.../Odata.svc) and I don't want the whole site under windows auth, but on the service at the url!
(I actually have this scenario for my app)
I can't thank you enough, the authentication parts for OData have been of immense help. Wish I was first here!
Please push up your blog rankings in MSDN Blogs directory.
Why not provide a link to part 1 of the article? it would be helpful
It is very surprising that you would not provide a link to all the articles in this series !
Please shed some light about how to perform authentication for ios apps which will be using the ODATA sdk fo r ios
This article is EXACTLY what I needed.
It would be really helpful to provide a case which is not from a windows client - e.g. from java (android) - how would it authenticate? thanks.
I tried to use ctx.UseDefaultCredentials = true; but it is not working.
My web service hosted in another sub domain. Pls help me.
Thanks for this article... It helped me solve a problem of an MVC app calling an OData service.