Twitter GitHub Facebook Instagram dirv.me

Daniel Irvine on building software

Authorizing REST requests with OpenRasta

30 June 2011

Over the next few posts I’ll discuss how I’ve implemented a variety of HTTP and REST features using OpenRasta. Being somewhat of an OpenRasta novice I can’t say that I’ve solved these problems in the best way possible, or even with total correctness, but the solutions work well enough.

For those new to OpenRasta, the system is underpinned by its pipeline model. An HTTP request is received and flows through the pipeline, being processed and modified in various ways before coming out as an HTTP response at the other end. Somewhere in the middle of this pipeline is the resource handler, which is the object that does the real work of processing your request. Generally you’ll have one resource handler class for each domain object in your system, and it’s often the class you’ll implement first when you begin writing your service.

But somewhere along the way, around about the time you implement your second or third resource handler, you’ll realize you’re repeating yourself. Each resource needs to be validated, each resource action needs to be authorized, action parameters need to be validated, et cetera. You’ll be following the same patterns for each resource.

But our first tenet is Don’t Repeat Yourself, right?

Luckily OpenRasta keeps us on the straight and narrow. It calls a special object called the OperationInterceptor before and after the resource handler runs. The interceptor has the opportunity to change the response entirely, and to exit out of the pipeline if necessary (for example, to deliver a Bad Request response). Diagrammatically it can be thought of in the following way.

OpenRasta's pipeline model

For the remainder of this post I’ll look at authorization, and in subsequent posts I’ll look at the other steps.

Resource-aware authorization I’ve defined an IAuthorizable interface that resources can implement if they are authorizable (perhaps by checking permissions in a database, for example).

interface IAuthorizable {
	string RequiredPermission { get; }
	string UserName { get; }    // provided as a result of authentication
}

How the UserName gets populated is a story for another day, but assume for now that the resource request knows about it. Next up, we have an IAuthorizer, which is the component that actually does the authorization of an IAuthorizable.

interface IAuthorizer {
	bool IsAuthorized(IAuthorizable authorizable);
}

How you implement these classes is up to you and entirely dependent on your system. But given these interfaces, you can write an OperationInterceptor that authorizes in the following way.

public class AuthorizationInterceptor : OperationInterceptor
{
	readonly ICommunicationContext _context;
	readonly IAuthorizer _authorizer;

	public AuthorizationInterceptor(
		ICommunicationContext context,
		IAuthorizer authorizer)  {
		_context = context;
		_authorizer = authorizer;
	}

	public override bool BeforeExecute(IOperation operation) {
		var input = operation.Inputs.FirstOrDefault();
		if (input == null) return true;

		var parameter = input.Binder.BuildObject();
		var authorizable = parameter.Instance as IAuthorizable;
		if(authorizable != null) {
			if(!_authorizer.IsAuthorized(authorizable)) {
				_context.OperationResult
					= new OperationResult.Forbidden();
				return false;
			}
		}
	}
}

A quick walkthrough of the code: firstly, if the resource doesn’t implement IAuthorizable, it returns true, meaning the resource handler gets called and everything continues as normal. This is especially important because chances are that not all your resources require authorization (especially if you have an “entry” resource into your system that is accessible by all).

If IsAuthorized returns false, we return a 403 Forbidden response.

One word of warning, if your IAuthorizer does anything useful at all, you’ll probably want to handle errors. If your authorizer can’t reasonably make a choice—for example, let’s say the permission database can’t be accessed and throws an exception—then you must, must, must return a failure code: either 403 Forbidden, or more appropriately 500 Internal Server Error. This code isn’t shown here but it’s not hard to add: just wrap the call to IsAuthorized in a try/catch block.

Finally, you may wonder why I’m returning a 403 Forbidden and not a 401 Unauthorized. I’ll cover that in my next post.

About the author

Daniel Irvine is a software craftsman at 8th Light, based in London. These days he prefers to code in Clojure and Ruby, despite having been a C++ and C# developer for the majority of his career.

For a longer bio please see danielirvine.com. To contact Daniel, send a tweet to @d_ir or use the comments section below.

Twitter GitHub Facebook Instagram dirv.me