US / UK-EMEA / Contact Ask DevelopMentor a Question800.699.1932

What I like and don't like about WIF’s Claims-based Authorization

by Dominick Baier

What I like

In “traditional” .NET with its IPrincipal interface and IsInRole method, developers were encouraged to write code like this:

public
 void AddCustomer(Customer
 customer)
{
    if (Thread.CurrentPrincipal.IsInRole("Sales"
))
    {
        // add customer

    }
}

In code reviews I’ve seen tons of code like this. What I don’t like about this is, that two concerns in your application get tightly coupled: business and security logic.

But what happens when the security requirements change – and they will (e.g. members of the sales role and some other people from different roles need to create customers)? Well – since your security logic is sprinkled across your project you need to change the security checks in all relevant places (and make sure you don’t forget one) and you need to re-test, re-stage and re-deploy the complete app. This is clearly not what we want.

WIF’s claims-based authorization encourages developers to separate business code and authorization policy evaluation. This is a good thing. So the same security check with WIF’s out-of-the box APIs would look like this:

public
 void AddCustomer(Customer
 customer)
{
    try

    {
        
ClaimsPrincipalPermission.CheckAccess("Customer","Add");
 
        // add customer

    }
    
catch (SecurityException ex)
    {
        // access denied

    }
}

You notice the fundamental difference? The security check only describes whatthe code is doing (represented by a resource/action pair) – and does not statewho is allowed to invoke the code. As I mentioned earlier – the who is most probably changing over time – the what most probably not.

The call to ClaimsPrincipalPermission hands off to another class called theClaimsAuthorizationManager. This class handles the evaluation of your security policy and is ideally in a separate assembly to allow updating the security logic independently from the application logic (and vice versa).

The claims authorization manager features a method called CheckAccess that retrieves three values (wrapped inside an AuthorizationContext instance) – action (“add”), resource (“customer”) and the principal (including its claims) in question. CheckAccess then evaluates those three values and returns true/false.

I really like the separation of concerns part here. Unfortunately there is not much support from Microsoft beyond that point. And without further tooling and abstractions the CheckAccess method quickly becomes *very* complex. But still I think that is the way to go.
In the next post I will tell you what I don’t like about it (and how to fix it).

What I don't like

In my last post I wrote about what I like about WIF’s proposed approach to authorization – I also said that I definitely would build upon that infrastructure for my own systems. But implementing such a system is a little harder as it could be. Here’s why (and that’s purely my perspective):
First of all WIF’s authorization comes in two “modes”
  • Per-request authorization.
    When an ASP.NET/WCF request comes in, the registered authorization manager gets called. For SOAP the SOAP action gets passed in. For HTTP requests (ASP.NET, WCF REST) the URL and verb.
  • Imperative authorization
    This happens when you explicitly call the claims authorization API from within your code. There you have full control over the values for action and resource.
In ASP.NET per-request authorization is optional (depends on if you have added the ClaimsAuthorizationHttpModule). In WCF you always get the per-request checks as soon as you register the authorization manager in configuration.

I personally prefer the imperative authorization because first of all I don’t believe in URL based authorization. Especially in the times of MVC and routing tables, URLs can be easily changed – but then you also have to adjust your authorization logic every time. Also – you typically need more knowledge than a simple “if user x is allowed to invoke operation x”.

One problem I have is, both the per-request calls as well as the standard WIF imperative authorization APIs wrap actions and resources in the same claim type. This makes it hard to distinguish between the two authorization modes in your authorization manager. But you typically need that feature to structure your authorization policy evaluation in a clean way.

The second problem (which is somehow related to the first one) is the standard API for interacting with the claims authorization manager. The API comes as an attribute (ClaimsPrincipalPermissionAttribute) as well as a class to use programmatically (ClaimsPrincipalPermission). Both only allow to pass in simple strings (which results in the wrapping with standard claim types mentioned earlier). Both throw a SecurityException when the check fails.

The attribute is a code access permission attribute (like PrincipalPermission). That means it will always be invoked regardless how you call the code. This may be exactly what you want, or not.
In a unit testing situation (like an MVC controller) you typically want to test the logic in the function – not the security check.

The good news is, the WIF API is flexible enough that you can build your own infrastructure around their core. For my own projects I implemented the following extensions:
  • A way to invoke the registered claims authorization manager with more overloads, e.g. with different claim types or a completeAuthorizationContext.
  • A new CAS attribute (with the same calling semantics as the built-in one) with custom claim types.
  • A MVC authorization attribute with custom claim types.
  • A way to use branching – as opposed to catching a SecurityException.
Connect
Signup for our Free Newsletter!
Latest news
Twitter Feed MORE
Got an email from a developer in Holland about my Onion Architecture blog post http://t.co/Z5DTvJob Nice to have a worldwide audience! #dm
1 day ago (details)
There is something to this statement: Why Quit? Because They Have Bigger Monitors http://t.co/9FrGETG5 #dm (via @mkennedy)
2 days ago (details)
Testimonials
  • Rod da Silva felt very confident in his product knowledge and experience. Bob C.