Authorization is a difficult topic. The implementation is typically so application/developer specific, that when you ask ten people how they do it, you most likely get ten different answers. I think this is also the reason why .NET does not include a “real” authorization framework besides providing some building blocks (e.g. roles and claims). When working at the claims guide for Microsoft we even shied away from writing a “best practices” chapter on that topic.
Because of that, everybody is building his own little framework around authorization – sometime simple sometimes with humongous complexity. And when you give feedback to such a system, you will most likely hurt somebody’s feelings.
Below are some observations around authorization and patterns I identified while working with our customers.
Fine vs. coarse grained
This is an obvious one. Coarse grained authorization mechanisms are indeed implemented in .NET. Coarse grained basically means that you do authorization at a very early stage in the pipeline. Typically around the question: “is user X allowed to access resource Y”. Details of that resource access (like specific parameters passed in) are typically not known at this early stage. Some examples are:
- The ASP.NET <authorization /> configuration element. It restricts access to URLs or pages (and verbs) based on roles.
- The .NET [PrincipalPermission] attribute restricts access to methods and classes based on roles.
- The WCF service authorization manager restricts access to SOAP actions based on roles (and claims).
- The WIF claims authorization manager has a coarse grained mode where you can restrict access to SOAP actions or URLs/verbs based on claims.
- The ASP.NET MVC/Web API [Authorize] attribute restricts access to controllers or action methods based on roles.
Coarse grained authorization is very useful to specify a general access policy across multiple endpoints in your application. They also typically follow the pattern that you centralize your authorization policy in a single place.
Since this type of authorization typically runs before any deserialization or model binding has happened, you don’t get access to the actual payload. And this is by design, because you don’t really want to do anything expensive to find out the user isn’t authorized anyways. But many authorization decisions are indeed based on the data that you get send. This is where fine grained authorization comes into play.
Fine grained authorization typically happens “inside the method” – either on the façade or in the business logic. There you have full access to the context. This is the space where .NET does not have a lot to offer and where people do their own implementations.
A remarkable exception is the WIF/.NET 4.5 claims authorization manager infrastructure where authorization is abstracted using resource/action pairs. I like that approach, but unfortunately the API did not get much love from Microsoft, and without writing your own little supporting infrastructure you won’t have much fun (something I guess I will revisit in a future post).
Inline vs. Separate
What I really mean here is, is the authorization logic intermingled with the business logic, or can they be maintained, versioned and tested separately.
The big anti-pattern is this:
// business logic
// other business logic
What I really don’t like about this approach is, that the business logic code needs to have intimate knowledge about who is allowed to do what. Both business and authorization logic will separately change over time, mixing them makes the code hard to maintain.
There are numerous variations of that approach, including attributes (like [PrincipalPermission]) or “resource base classes” that implement the security checks.
The approach I’d recommend is keeping those concerns separate. The WIF/.NET 4.5 ClaimsAuthorizationManager uses that approach. There the business logic code is only telling the authorization system that “principal X tries to do Y” – and the authorization system figures out the rest. Ideally the configuration policy is implemented separately from the application code, so you can version them independently.
Going one step further, the authorization data may even be stored on a totally different system, and your application local plumbing only queries that system. Microsoft Authorization Manager (AzMan) used that approach when storing authorization rules in Active Directory. There are also XACML based systems, but this technology never got a lot of traction in the .NET/Windows space.
(The ideas in XACML btw are interesting as they have clean separations of concerns. I’d love to see a claims/rules based system built into Windows. Like AzMan v.Next.)
Obviously there are also a number of in-between implementations.
Finding the right balance…
between all these approaches is hard. And especially when you are trying to write re-usable code, you constantly struggle generalizing things too much and trying to abstract the too specific ones.
Which approach are you using? Am I missing something?