Implementing a REST-ful service using OpenRasta and OAuth WRAP with Windows Azure AppFabric ACS.

I’ve been building prototypes again and I wanted to build a service that exposed a fairly simple, resource-based data API with granular security, i.e. some of my users would be allowed to access one resource but not another or they might be allowed to read a resource but not create or update them.

To do this I’ve used OpenRasta and created an security model based on OAuth/WRAP claims issued by the Windows Azure AppFabric Access Control Service (ACS).

The client can now make a rest call to the ACS passing an identity and secret key. In return they will be issued with a set of claims. A typical claim encompasses a resource in my REST service and the action(s) the user is allowed to perform, so their claim set might show that they were allowed to execute GET against resource foo but not POST or PUT.

In my handler in OpenRasta I add method attributes that indicate what claims are required to invoke that method, for instance in my handler for resources of type foo I might have the following method  :

[RequiresClaims("com.somedomain.api.resourceaction", "GetFoo")]
public OperationResult GetFooByID(int id)
{
	//elided
}

In my solution I have created an OpenRasta interceptor which examines inbound requests, validates the claim set and then compares the claims required by the method attribute to the claims in the claim set. Only if there is a match can the request be processed.

After a few tweets with @serialseb I refactored the above into an IAuthenticationScheme that validates the claims, leaving the original OperationInterceptor to check the claims required by the method to be invoked. I also added an extension method so that the whole thing can be fluently configured like so :

ResourceSpace.Uses.AzureClaimsAuthenticationScheme();

I was going to write a long blog post about how to build this from scratch with diagrams and screen shots and code samples but I found that I couldn’t be arsed. If you’d like more info more on how to do this just drop me a line. In the meantime I’ve dropped the source files as follows :