What I don’t like about WIF’s Claims-based Authorization
- by Your DisplayName here!
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 complete AuthorizationContext.
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.
I will post the code for these various extensions here – so stay tuned.