Resource/Action based Authorization for OWIN (and MVC and Web API)

Authorization is hard – much harder than authentication because it is so application specific. Microsoft went through several iterations of authorization plumbing in .NET, e.g. PrincipalPermission, IsInRole, Authorization configuration element and AuthorizeAttribute. All of the above are horrible approaches and bad style since they encourage you to mix business and authorization logic (aka role names inside your business code).

WIF’s ClaimsPrincipalPermission and ClaimsAuthorizationManager tried to provide better separation of concerns – while this was a step in the right direction, the implementation was “sub-optimal” – based on a CLR permission attribute, exception based, no async, bad for unit testing etc…

In the past Brock and me worked on more modern versions that integrate nicer with frameworks like Web API and MVC, but with the advent of OWIN/Katana there was a chance to start over…

Resource Authorization Manager & Context
We are mimicking the WIF resource/action based authorization approach – which proved to be general enough to build your own logic on top. We removed the dependency on System.IdentityModel and made the interface async (since you probably will need to do I/O at some point). This is the place where you will centralize your authorization policy:

public interface IResourceAuthorizationManager

{

    Task<bool> CheckAccessAsync(ResourceAuthorizationContext context);

}

 

(there is also a ResourceAuthorizationManager base class with some easy to use helpers for returning true/false and evaluations)

The context allows you to describe the actions and resources as lists of claims:

public class ResourceAuthorizationContext
{
    public IEnumerable<Claim> Action { get; set; }
    public IEnumerable<Claim> Resource { get; set; }
    public ClaimsPrincipal Principal { get; set; }
}

 

Middleware
The corresponding middleware makes the authorization manager available in the OWIN enviroment:

public void Configuration(IAppBuilder app)
{
    var cookie = new CookieAuthenticationOptions
    {
        AuthenticationType = "Cookie",
        ExpireTimeSpan = TimeSpan.FromMinutes(20),
        LoginPath = new PathString("/Login"),
    };
    app.UseCookieAuthentication(cookie);
 
    app.UseResourceAuthorization(new ChinookAuthorization());
}

 

Usage
Since the authorization manager is now available from the environment (key: idm:resourceAuthorizationManager) you can get ahold of it from anywhere in the pipeline, construct the context and call the CheckAccessAsync method.

The Web API and MVC integration packages provide a ResourceAuthorize attribute for declarative checks:

[ResourceAuthorize(ChinookResources.AlbumActions.View, ChinookResources.Album)]

 

And several extension methods for HttpContextBase and HttpRequestMessage, e.g.:

if (!HttpContext.CheckAccess(
    ChinookResources.AlbumActions.Edit,
    ChinookResources.Album,
    id.ToString()))
{
    return new HttpUnauthorizedResult();
}

 

or..

var result = Request.CheckAccess(
    ChinookResources.AlbumActions.Edit,
    ChinookResources.Album,
    id.ToString());

 

Testing authorization policy
Separating authorization policy from controllers and business logic is a good thing, centralizing the policy into a single place also has the nice benefit that you can now write unit tests against your authorization rules, e.g.:

[TestMethod]
public void Authenticated_Admin_Can_Edit_Album()
{
    var ctx = new ResourceAuthorizationContext(User("test", "Admin"),
        ChinookResources.AlbumActions.Edit,
        ChinookResources.Album);
    Assert.IsTrue(subject.CheckAccessAsync(ctx).Result);
}

 

or…

[TestMethod]
public void Authenticated_Manager_Cannot_Edit_Track()
{
    var ctx = new ResourceAuthorizationContext(User("test", "Manager"),
        ChinookResources.TrackActions.Edit,
        ChinookResources.Track);
    Assert.IsFalse(subject.CheckAccessAsync(ctx).Result);
}

 

Code, Samples, Nuget
The authorization manager, context, middleware and integration packages are part of Thinktecture.IdentityModel – see here.

The corresponding Nuget packages are:

..and here’s a sample using MVC (if anyone wants to add a Web API to it – send me a PR).

This entry was posted in ASP.NET, IdentityModel, Katana, OWIN, WebAPI. Bookmark the permalink.

39 Responses to Resource/Action based Authorization for OWIN (and MVC and Web API)

  1. larry says:

    I downloaded the ResourceAuthorizationSample and am seeing a problem with the Claim.Properties property.

    If I edit the InMemoryClaimsRepository’s GetClaimsForUser method and add a test key-value pair onto the Claim.Properties property, it is not there when I later check for it in the ChinookAuthorization’s CheckAccessAsync override method. The Claim is there but the Properties property is empty.

    Is there anything special I need to do to have the Claims.Property “persist” in the Claim?

  2. Raf says:

    1) So this is your recommended way to perform granular authorization?

    I’m still new to the IdentityServer.3 approach but I certainly will use it on the application I’m working on. And I am trying to understand what is the best possible way to perform granular authorization.

    My app has tons of actions/resources so I will need to store this inside a database so Im guessing I will have to implement my own version of ResourceAuthorizationManager.

    2) If I were to use this approach with IdentityServer.3 that means I will have to use the claims (or scopes?) returned on the token instead of having my own ClaimRepository implementation. Right?

  3. Khaled Hammouda says:

    How do I combine resource authorization with OAuth bearer token authentication?

    Previously I had this in my OWIN configuration:

    app.UseOAuthBearerAuthentication( new OAuthBearerAuthenticationOptions {} );

    And my controller:

    [Authorize]
    public class IssuesController : ApiController {

    }

    The [Authorize] attribute caused the OAuth token validation to be enforced, so this part was fine.

    Now I have:

    app.UseOAuthBearerAuthentication( new OAuthBearerAuthenticationOptions {} );
    app.UseResourceAuthorization( new MyAuthorizationManager() );

    [ResourceAuthorize( “Access”, “Things” )]
    public class IssuesController : ApiController {

    }

    But now the OAuth token validation doesn’t work. If I add the [Authorize] attribute to the controller it works. So is this how it’s supposed to be:

    [Authorize]
    [ResourceAuthorize( “Access”, “Things” )]
    public class IssuesController : ApiController {

    }

    Seems a bit redundant to me to require to authorization attributes to have this work, because from your example you seem to be able to achieve both resource authorization and cookie authentication by just using the ResourceAuthorizeAttribute.

  4. Pingback: Common authentication/authorization between .NET4.0 and .NET4.5 web applications | Low Level Design

  5. Vassago says:

    Hi,

    Hopefully this is a simple yes/no question. I’ll admit that I haven’t downloaded your sample projects yet, so please excuse any ignorance displayed :)

    I have a requirement to be able to authorise a user’s access to individual the properties and methods of a particular /instance/ of an object they are accessing… i.e. not just the /type/ of object they are accessing. My specific scenario is that Users can have a maximum of one type of relationship with an Account. E.g. they could be the “AccountHolder” of the Account, the “AccountOpertor”, the “AccountViewer”, etc. They could also have different relationships to different Accounts and these relationship types could change over time.

    Whenever a user selects an account, I need to work out whether or not to display the Balance to them. In other words, I would need to know whether the current user has permission to access the Balance property of the particular Account object that I have just fetched. This will depend on their type of relationship with that Account.

    I have been able to do such “instance level” authorisation in the past using the CSLA business framework, but this has fallen out of favour in my company as we’ve moved towards MVC, IOC etc. (but that’s another argument ;). Anyway, whilst looking into alternative frameworks, I’ve struggled to find one that would support the scenario I described above so I was wondering if you could give me a quick answer: Can the IdentityServer.3 framework support instance level authorisation?

    Thanks

    P.S. In case it matters, this will be a .NET 4.5 project deployed on Windows Server 2012 using ASP.NET MVC 5 for the web front end and Entity Framework 6 for data access to a SQL Server back-end. Not decided on a “middle tier” business framework yet.

    • The simple answer is no – IdentityServer3 is a token service, not an authorization framework.

      For the long answer – check out the sample projects ;)

    • Take a look at the VITA authorization framework: https://vita.codeplex.com/wikipage?title=guide_authorization&referringTitle=Home

      I haven’t used it personally, and it looks like a swiss army knife, so I can’t endorse it. I’m just sharing a resource that seems to do what you want, and possibly provide you with insight into how to do it if you were to do it on your own.

      • Vassago says:

        Thanks Khaled, that looks really interesting. I especially like the split between ‘peek’ and ‘read’… Can’t believe I never thought of that myself!… and also the idea of granting access with a using statement only for a specific purpose.

        Not sure how well the ‘SecureSession’ will play with our IOC framework but I can certainly see us using some of its ideas if not the whole framework.

        Thanks again

  6. I can’t find any documentation for using ResourceAuthorize in Asp.Net 5. Which is shocking, considering that Asp.Net 5 has been in RTW for a full day already ;-)
    Do you have any plans to support Asp.Net 5 (MVC6)? If you already do, could you please point me to some documentation on how to set this up?

    • AspNet5 is still beta. They are working on a similar feature for authZ themselves. No idea what the status is. We have no plans currently to port our stuff.

      • You are right, it is still beta. I saw the announcement on the start page of Visual Studio and didn’t bother reading the entire article…
        Is there anything public on for Microsoft’s authZ effort? I didn’t find anything relevant by googling.

  7. Saw it on github (security repo)

  8. percollin says:

    Why does the ResourceAuthorizeAttribute in Thinktecture.IdentityModel,Mvc wait by default for 5000 ms before throwing a timeout exception in the CheckAccess method:

    protected virtual bool CheckAccess(HttpContextBase httpContext, string action, params string[] resources)
    {
    Task task = HttpContextExtensions.CheckAccessAsync(httpContext, action, resources);
    if (task.Wait(5000))
    return task.Result;
    throw new TimeoutException();
    }

    Is there anyway to go around this? What if I want to debug my ResourceAuthorizationManager?

  9. Well – we essentially need to call async code from sync code. We need a timeout.

  10. Matt says:

    Can I ask a question about MVC views. I understand how to setup a ‘ResourceAuthorize’ attribute on a controller action. I’m pulling down the claims and transforming them so they’re available to the User object in an MVC view.

    Is it possible to use the ResourceAuthorize attribute inside a view? I currently have to use roles directly in the views (e.g. @if (User.IsInRole(“CanAccessSite”)).

    • You can use the programmatic approach. But it would be better style if your view model would contain all relevant information and view would just do the rendering based on that.

  11. Matt says:

    Thanks. That makes sense. I was interrogating roles in the Layout so will have to re-design a little. But putting them in the ViewModel appears the neater solution anyway.

  12. How do I implement this if I had the access permissions stored in a database?

  13. duribe76 says:

    Dominick, I can’t find the MVC/WebApi authorization library in the most recent IdentityModel project in Github or Nuget, the ones without the Thinktecture prefix. Is there a plan to bring it back?

    • It’s in the thinktecture version and there are nugets. We are not actively maintaining it anymore, but feel free to copy the source code.

      • duribe76 says:

        Really appreciate the quick response, I knew it was still available in the Thinktecture version. but since my project references the new IdentityModel, I didn’t want to introduce any conflicts by having both. Thanks for the suggestion about the source code, I may decide to copy or at least base our implementation on it.

  14. phuong says:

    Hi Dominick,
    I have applied the ResourceAuthorization to my MVC project. it worked ok. (TestController)
    I want to apply ResourceAuthorization for WebApi (in same project).
    It does not run into CheckAccessAsync()
    Can u help me, or give me an sample project
    Tks

    • you know that there are two separate attributes – one for MVC and one for Web API?

    • stt106 says:

      Hi phuong, did you get the package working for a web api project? I am trying to use it in a web api project but couldn’t get it working. Do you have any sample project you can share?
      The error I got was: “No authorisation manager set”.
      I created a subclass from ResourceAuthorisationManager and registered it with owin middleware; is there anything else I need to do?
      Thanks.

  15. Samuel says:

    Nice work guys, this is great! quick question: is there a possibility to have access to the HttpContext inside the authorizationmanager? it seems that the parameters for Odata queries are not added to the ResourceAuthorizationContext which would be necessary in order to authorize depending on the query that was made…
    Thanks again!

    • Thanks!

      I don’t think this is “built-in” right now. We stopped working on it because we already have enough OSS projects to maintain.

      Feel free to extend it – or use the hacky way via HttpContext.Current.

      • K.P. says:

        Can you advise on what’s currently best to use for authorization?
        Because the Thinktecture.IdentityModel package officially states [deprecated] and in the ‘Part 1 – MVC Authentication & Authorization’ tutorial it says it’s not recommended to use the ASP.NET Authorize attribute.

        I get that you have enough projects to maintain, but what will you use for IdentityServer4[.Samples]?

        Thanks!

      • Maybe deprecated is a too strong word. We just don’t maintain it anymore. If it works for you, feel free to use the code.

        For ASP.NET Core, the new authorization API is the recommended approach – it is based on our old library, but much more feature rich.

  16. Lars M says:

    It seems that HttpContext.Current is null in the ResourceAuthorizationManager class when the call from a controller is made this way:
    HttpContext.CheckAccess(ChinookResources.AlbumActions.Edit, ChinookResources.Album, id.ToString())

    and HttpContext.Current has a value when the call is made this way:
    [ResourceAuthorize(ChinookResources.AlbumActions.View, ChinookResources.Album)]

    1. Does this match your findings?
    2. Are there any other way to get hold of the HttpContext.Current in the ResourceAuthorizationManager class?

    (I’m trying to get to the HttpContext.Current.GetOwinContext().GetUserManager() object from inside the ResourceAuthorizationManager class)

    Thanks

  17. raffaeu says:

    If you are on Identity Server 4, most of the “dirty job” is already done.
    You have Clients, Scope and Claims.
    So you can provide a first “authentication” entry point, quite fine grained if you consider the possible combinations that multiple Clients/Scope/Resources can give to you.

    The second step is “authorization” and in ASP.NET Core can be accomplished also by using Claims together with Policies and Roles and it is well described here:
    https://docs.microsoft.com/en-us/aspnet/core/security/authorization/claims

    I think that Identity Server 4.x should provide an easy integration of this concept so that it can be easily blended together with ASP.NET Core authorization, which is already available.

  18. stt106 says:

    Hi Dom, I tried to use the nuget package for a web api project; but got an error saying: “No AuthorizationManager set.” The CheckAccessAsync method is not called.

    I created a class TestAuthManager which is subclassed from ResourceAuthorisationManager and register the middleware in the Startup with app.UseResourceAuthorisation(new TestAuthManager()).

    Is there anything else I need to do in a web api project?
    Thanks.

Leave a comment