OData and Authentication – Part 3 – ClientSide Hooks

DB Blogs

So far in this series we’ve looked at Windows Authentication.

For both Windows and Basic Authentication, Data Services does the authentication handshake and subsequent sending of authentication headers – all without you directly setting a http header.

It can do this because there is a higher level abstraction – the Credentials property – that hides the implementation details from you.

All this works great for Windows and Basic Authentication. However if you are using a different authentication scheme, for arguments sake OAuth WRAP, the Credentials property is of no use. You have to get back down to the request and massage the headers directly.

You might need to set the request headers for all sorts of reasons, but probably the most common is Claims Based Authentication.

So before we look into how to set the headers, a little background…

Claims based Authentication 101

The basic idea of Claims Based Auth, is that you authenticate against an Identity Provider and request an ‘access token’ which you can use to make requests against a server of protected resources.

The server – essentially the gatekeeper – looks at the ‘access token’ and verifies it was issued by an Identity Provider it trusts, and if so, allows access to the resources.

Keeping the claim private

Any time you send a token on the wire it should be encrypted, so that it can’t be discovered and re-used by others. This means claims based authentication – at least in the REST world – generally uses HTTPS.

Many Authentication Topologies

While the final step – setting the access token – is very simple, the process of getting an authentication token can get much more complicated, with things like federated trust relationships, delegated access rights etc.

In fact, there are probably hundreds of ‘authentication topologies’ that can leverage claims based authentication. And each topology will involve a different process to acquire a valid ‘access token’.

We’re not quite ready to cover these complexities yet, but we will revisit the specifics in a later post.

Still, at the end of the day, the client application simply needs to pass a valid access token to the server to gain access.

Example Scenario: OAuth WRAP

So if for example you have an OData service that uses OAuth WRAP for authentication the client would need to send a request like this:

GET /OData.svc/Products(1)
Authorization: WRAP access_token=”123456789”

And the server would need to look at the Authorization header and decide if the provided access_token is valid or not.

Sounds simple enough.

The real question for today is how do you set these headers?

Client Side Hooks

Before making requests

On the client-side adding the necessary headers is pretty simple.

Both the Silverlight and the .NET DataServiceContext have an event called SendingRequest that you can hook up to. And in your event handler you can add the appropriate headers.

For OAuth WRAP your event handler might look something like this:

void OnSendingRequest(object sender, SendingRequestEventArgs e)
{
    e.RequestHeaders.Add(“Authorization”,”WRAP access_token=\”123456789\””);
}

What if the Access Token is invalid or missing?

If the Access Token is missing or invalid the server will respond with a 401 unauthorized response, which your code will need to handle.

Unfortunately in the Data Services client today there is no place to hook into the HttpResponse directly, so you have to wait for an Exception.

You will get either a DataServiceQueryException or DataServiceRequestException depending on what you were doing, and both of those have a Response property (which is *not* a HttpResponse) that you can interrogate like this:

try
{
    foreach (Product p in ctx.Products)
        Console.WriteLine(p.Name);
}
catch (DataServiceQueryException ex)
{
    var scheme = ex.Response.Headers[“WWW-Authenticate”];
    var code = ex.Response.StatusCode;
    if (code == 401 && scheme == “WRAP”)
        DoSomethingToGetAnOAuthAccessToken();
}

The problem with trying to get an Access Token when challenged like this, rather than up front before you make the request, is that you now have to go and acquire a valid token, and somehow maintain context too, so the user isn’t forced to start again.

It is also a little unfortunate that you can’t easily centralize this authentication failure code.

Summary

As you can see it is relatively easy to add custom headers to requests, which is ideal for integrating with various auth schemes on the client side.

It is however harder to look at the response headers. You can do it, but only if you put try / catch blocks into your code, and write code to handle the UI flow interruption.

So our recommendation is that you get the necessary tokens / claims etc – for example an OAuth access_token – before allowing users to even try to interact with the service.

In Part 4 we will look at the Server-Side hooks…

Alex James
Program Manager
Data Service Team

0 comments

Discussion is closed.

Feedback usabilla icon