The State of Security in ASP.NET 5 and MVC 6: Authorization

The hardest part in designing an application is authorization. The requirements are always so app-specific that for 10 applications you often see 12 different implementations.

To make things worse, ASP.NET and MVC traditionally had not much more built-in to offer than boring role checks. This lead to either unmaintainable code (hard coded role names and Authorize attributes) or complete custom implementations – or both.

In ASP.NET 5, a brand new authorization API is supposed to improve that situation – and IMHO – oh yes it does. Let’s have a look.

Overview
ASP.NET 5 supports two styles of authorization out of the box – policy-based and resource-based.

Both styles are a substantial improvement over the current ASP.NET authorization features and reduce the need to write your own authorization attribute/filter/infrastructure – though this is still totally possible.

The new Authorize Attribute
My main gripe with the old attribute is that it pushes developers towards hard-coding roles (or even worse – names) into their controller code. It violates separation of concerns and leads to hard to maintain code with roles names sprinkled all over your code base.

Also – let’s face it – declarative, role-based security might be nice for demos but is nowhere near flexible enough to write  anything but trivial applications.

The new Authorize attribute can still do role checks like this:

[Authorize(Roles = "Sales")]
public IActionResult DoSalesyStuff()
{ /* .. */ }

But this is mainly for backwards compatibility (the ability to check for names is gone). The more recommended pattern is to use so called authorization policies instead:

[Authorize("SalesOnly")]
public IActionResult DoSalesyStuff()
{ /* .. */ }

Let’s have a look at policies next.

Policies & Requirements
Policies are a way to create re-usable authorization logic. Policies consist of one or more so called requirements. If all requirements of a policy are met, the authorization check is successful – otherwise it fails.

Policies are created using a policy builder, and the following snippet creates a very simple policy (aka “require authenticated users”) and sets that globally in MVC:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // only allow authenticated users
        var defaultPolicy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .Build();
 
        services.AddMvc(setup =>
        {
            setup.Filters.Add(new AuthorizeFilter(defaultPolicy));
        });
    }
}

There are more extension methods similar to RequireAuthenticatedUser – e.g. RequireClaim or RequireRole.

Another common use case are named policies which can be referenced like the above SalesOnly example (again in Startup.ConfigureServices):

services.AddAuthorization(options =>
{
    // inline policies
    options.AddPolicy("SalesOnly", policy =>
    {
        policy.RequireClaim("department""sales");
    });
    options.AddPolicy("SalesSenior", policy =>
    {
        policy.RequireClaim("department""sales");
        policy.RequireClaim("status""senior");
    });
});

You can also encapsulate requirements in classes, e.g.:

public class StatusRequirement : AuthorizationHandler<StatusRequirement>, IAuthorizationRequirement
{
    private readonly string _status;
    private readonly string _department;
 
    public StatusRequirement(string department, string status, bool isSupervisorAllowed = true)
    {
        _department = department;
        _status = status;
    }
 
    protected override void Handle(AuthorizationContext context, StatusRequirement requirement)
    {
        if (context.User.IsInRole("supervisor"))
        {
            context.Succeed(requirement);
            return;
        }
 
        if (context.User.HasClaim("department", _department) &&
            context.User.HasClaim("status", _status))
        {
            context.Succeed(requirement);
        }
    }
}

Which can then be added like this:

options.AddPolicy("DevInterns", policy =>
{
    policy.AddRequirements(new StatusRequirement("development""intern"));
 
    // ..or using an extension method
    //policy.RequireStatus("development", "intern");
});

Under the covers, the AddAuthorization extension method also puts an IAuthorizationService (or more specifically the DefaultAuthorizationService) into the DI container. This class can be used to programmatically evaluate policies (amongst other things – more on that later).

To make the authorization service available – simply add it to e.g. a controller constructor:

public class TestController : Controller
{
    private readonly IAuthorizationService _authz;
 
    public TestController(IAuthorizationService authz)
    {
        _authz = authz;
    }
}

..and then use it in an action:

public async Task<IActionResult> SalesSeniorImperative()
{
    if (await _authz.AuthorizeAsync(User, "SalesSenior"))
    {
        return View("success");
    }
 
    return new ChallengeResult();
}

Scott used a slightly different approach, but using the same underlying infrastructure.

Remark ChallengeResult can be used to trigger an “access denied” condition in MVC. The cookie middleware e.g. will translate that either into a redirect to a login page for anonymous users, or a redirect to an access denied page for authenticated users.

Remark 2 Since views in MVC 6 also support DI, you can inject the authorization service there as well. Some people like this approach to conditionally render UI elements.

@{
    ViewData["Title"] = "Home Page";
    
    @using Microsoft.AspNet.Authorization
    @inject IAuthorizationService _authz
}
 
@if (await _authz.AuthorizeAsync(User, "SalesOnly"))
{
    <div>
        <a href="test/salesOnly">Sales only</a>
    </div>
}

This is a nice way to centralize authorization policies and re-use them throughout the application.

The only thing I don’t like about this approach is, that it pushes you towards using the claims collection as the sole data source for authorization decisions. As we all know, claims describe the identity of the user, and are not a general purpose dumping ground for all sorts of data – e.g. permissions.

It would be nice if one could use the DI system of ASP.NET to make further data source accessible in custom requirement. I’ve opened an issue for that – we’ll see what happens.

Resource-based Authorization
This is a new approach for ASP.NET and is inspired by the resource/action based approach that we had in WIF before (which was ultimately inspired by XACML). We also like that approach a lot, but the problem with the WIF implementation (and also ours) was always that due to the lack of strong typing, the implementation became messy quickly (or at least you needed a certain amount of discipline to keep it clean over multiple iterations).

The idea is simple – you identify resources that your application is dealing with – e.g. customers, orders, products (yawn). Then you write a so called handler for each of these resources where you express the authorization requirements in code.

You use requirements to express whatever action is supposed to be applied to the resource, and conclude with a success/failure, e.g.:

public class CustomerAuthorizationHandler : 
    AuthorizationHandler<OperationAuthorizationRequirementCustomer>
{
    protected override void Handle(AuthorizationContext context, 
        OperationAuthorizationRequirement requirement, 
        Customer resource)
    {
        // implement authorization policy for customer resource
    }
}

Operation requirements are built-in and can be used to model simple string-based actions – but you can also write your own, or derive from OperationAuthorizationRequirement.

public static class CustomerOperations
{
    public static OperationAuthorizationRequirement Manage = 
        new OperationAuthorizationRequirement { Name = "Manage" };
    public static OperationAuthorizationRequirement SendMail =
        new OperationAuthorizationRequirement { Name = "SendMail" };
 
    public static OperationAuthorizationRequirement GiveDiscount(int amount)
    {
        return new DiscountOperationAuthorizationRequirement
        {
            Name = "GiveDiscount",
            Amount = amount
        };
    }
}

You then register the resource handler with the DI system and can access it imperatively from within your controllers (using the above mentioned authorization service):

public async Task<IActionResult> Discount(int amount)
{
    var customer = new Customer
    {
        Name = "Acme Corp",
        Region = "south",
        Fortune500 = true
    };
 
    if (await _authz.AuthorizeAsync(User, customer, 
        CustomerOperations.GiveDiscount(amount)))
    {
        return View("success");
    }
            
    return new ChallengeResult();
}

What I like about this approach is that the authorization policy has full strong typed access to the domain object it implements authorization for, as well as the principal. This is a huge improvement over the WIF API. It also makes it easy to unit test your controller without the authorization code – and even more importantly (at least for security guy) – it allows unit testing the authorization policy itself.

protected override void Handle(AuthorizationContext context, 
    OperationAuthorizationRequirement requirement, 
    Customer resource)
{
    // user must be in sales
    if (!context.User.HasClaim("department""sales"))
    {
        context.Fail();
        return;
    }
 
    // ...and responsible for customer region
    if (!context.User.HasClaim("region", resource.Region))
    {
        context.Fail();
        return;
    }
 
    // if customer is fortune 500 - sales rep must be senior
    if (resource.Fortune500)
    {
        if (!context.User.HasClaim("status""senior"))
        {
            context.Fail();
            return;
        }
    }
 
    if (requirement.Name == "GiveDiscount")
    {
        HandleDiscountOperation(context, requirement, resource);
        return;
    }
 
    context.Succeed(requirement);
}

In addition, the resource handler can make full use of the DI system. That means we can inject access to arbitrary data stores. A very common use case is to use some sort of database to query permission tables or similar. This makes it very flexible.

Imagine a permission service that queries your authorization using some backing store (the _permissions variable):

private void HandleDiscountOperation(
    AuthorizationContext context, 
    OperationAuthorizationRequirement requirement, 
    Customer resource)
{
    var discountOperation = requirement as DiscountOperationAuthorizationRequirement;
    var salesRep = context.User.FindFirst("sub").Value;
 
    var result = _permissions.IsDiscountAllowed(
        salesRep,
        resource.Id,
        discountOperation.Amount);
 
    if (result)
    {
        context.Succeed(requirement);
    }
    else
    {
        context.Fail();
    }
}

All in all – I am very pleased with this new API and it will be interesting to see how it performs in a real application.

The full source code of the sample can be found here and the repo for the authorization API is here (open an issue if you have feedback)

Have fun!

This entry was posted in .NET Security, ASP.NET, WebAPI. Bookmark the permalink.

42 Responses to The State of Security in ASP.NET 5 and MVC 6: Authorization

  1. trailmax says:

    Thanks for this explanation! I’m glad this comes as a MVC-native implementation. I had to implement something like this with claims in MVC5 and it was not fun.

  2. jerriep says:

    Wow, great stuff thanks!

  3. David Peden says:

    “It would be nice if one could use the DI system of ASP.NET to make further data source accessible in custom requirement. I’ve opened an issue for that – we’ll see what happens.”

    Referenced issue: https://github.com/aspnet/Security/issues/297

  4. Mazher Uddin says:

    if I use resource based handler, i.e. AuthorizationHandler , how can I use Authorize attribute to pass the resource? I know that resource is resolved at runtime, not during compile time. The main reason I had to use this because in our application permissions are granted by the application itself. They can change at runtime. Since I cannot pass any arbitrary string to the authorize attribute other than the policy name, I don’t know how else I can figure out if a particular user has a particular permission through authorize attribute.

    • You don’t – you do it imperatively.

      • Mazher Uddin says:

        I tried to use resource based approach just because I could not do it through attribute. The fact is this is not resource we are talking about. All I am trying to figure out if I can set a policy where I would ask the custom handler for that policy that if the user belongs to any role that has permission to perform X. The thing that is important here, the permissions can be modified for roles at runtime.

    • Mazher Uddin says:

      Thanks. But don’t you think it’s a back step considering I was able to do it in previous version of asp.net by overriding the Authorize attribute?

      • No – resource authZ is all about knowing details about the resource – and this is only known “inside” the method and not in an authZ attribute that runs even before model binding.

  5. So why don’t you use a policy then?

    • Mazher Uddin says:

      Because I can only pass the name of the policy in the attribute. What I would like to do is Authorize(“PermissionPolicy”, “PerformX”);, But I can’t send additional parameter to authorize that I can retrieve back from the handler and check it against database to make sure the user has role associated with him that grants him the ability to perform X.

      • Karl Waclawek says:

        I agree with you. I am currently trying to port my previous AuthorizationFilterAttribute (WebApi 2) to the new framework, and it becomes almost impossible. I used to be able to simply decorate my API methods with a permissionattribute that contained a unique permissions code for the operation and it simply would check if the user has permissions for that specific API method (using user claims).

        Seems the AuthorizationAttribute approach is meant to support only a few specific scenarios – excluding the one I just described – and is not extensible because you can’t get at the attribute’s properties later on.

        I may have to go back to using a filter attribute.

      • Eqbal Sajadi says:

        + I have sane problrm

      • Nathan Alden, Sr. says:

        I have the exact same issue. My previous code: [CustomAuthorize(Permission.CreateFoo)] I am not sure why this obvious, common scenario seems to have been overlooked. The number of ways that claims in a JWT can be analyzed to determine if a principal is authorized is nearly infinite. Each action method should have very fine-grained control over the potentially complex algorithm of determining authorization. Even with Web API’s flexibility, oftentimes authorization simply must be performed in the action method for any number of reasons.

  6. Well – then open an issue for that on their repo.

  7. DynamicLynk says:

    You can do as you wish with a custom IAuthorizationRequirement implementation.

    My custom implementation.

    public class CustomAuthorizeRequirement: AuthorizationHandler, IAuthorizationRequirement

    then override
    protected override void Handle(AuthorizationContext context, CustomAuthorizeRequirement requirement)

    Middleware Usage:
    options.AddPolicy(RequirementPolicyConstants.StandardUserAccessPolicy, policy =>
    {
    SetDefaultAuthenticatedPolicies(ref policy);
    policy.AddRequirements(new CustomAuthorizeRequirement(appName)
    {
    UserRolesAllowed = new string[] { “StandardUser” },
    OtherCustomProps = Stuffs
    });
    });

    Controller Usage
    [Authorize(Policy = RequirementPolicyConstants.StandardUserAccessPolicy)]
    [HttpGet(“{id:int}”)]
    public async Task GetCommunity(int id)

  8. Sure doesn’t seem to make things easier than the mess that MVC 5 Identity alread had. Not everyone is a genius and this Identity stuff.

    It is driving away startups and programmers with good ideas. They can never get past the gate to actually build something that does something.

    • I don’t agree – but you probably expected that.

      The new authorization API is unrelated to ASP.NET Identity.

      Regardless how good the ideas of startups are – they probably need security – and security is hard (and authorization is the hardest part) – they better learn it, or they’ll be on the news.

    • Completely agree John. I am baffled at how much time we’ve spent on trying to implement authentication for a simple mobile app for our new startup (I have 5+ years of .NET experience and have previously built the full-end for my previous startup using ASP.NET in the MVC 3 era).

      We had to end up completely giving up and writing manual token generation and middleware handling, circumventing the WHOLE ASP.NET authentication system. This is absolutely ludicrous.

      Context: We needed to implement phone number based auth (generate temporary verification code based on a user’s phone number instead of traditional email/pass). Let’s just say the Identity framework and its gazillion abstractions fell flat on its face.

      • nathanalden says:

        Same here. Authorization is simply something that very, very rarely is one-size-fits-all. At least with Web API’s pipeline I could write a custom-derived AuthorizationFilterAttribute implementation that took params enums for permissions, permission groups, and even an operator (and/or) informing the attribute’s authorization algorithm. And it all *just worked*.

      • It’s best to raise your concerns in the github repo. The MS folks are hanging out there.

  9. Abhimanyu Kumar says:

    This works fine. Now I want to authenticate my web service calls with same approach. Suppose my application has 2 project – a web project and a web api and both are running on same domain like app.mydomain.com and service.mydomain.com

    During login from my web app, I am able to set claims and putting condition based on that in my web app controller. Now I want to do the same in web API and this web API can be called from Web project and/or JQuery also. Please guide.

    • how do you authenticate the web api calls?

      • Abhimanyu Kumar says:

        In my previous application, I used to generate a token after successful login and used to pass the same token in header of my service calls for authorization at service layer.

        Here also, I am trying to achieve similar things. Somehow I want to check if the claims added in web project after successful login can be used in web service layer (read the claims and decide whether to allow the access or not).

        Hope I make sense to your query,

  10. Well that sounds like you are inventing your own protocol and token format. That sounds dangerous. I would recommend you look into OpenID Connect and OAuth 2.0 for achieving the same using proven standards.

  11. Abhimanyu Kumar says:

    May be I am not able to explain the question properly – I want to check something like below in service layer.

    if (!context.User.HasClaim(“department”, “sales”))
    {
    context.Fail();
    return;
    }

    Can I access AuthorizationContext in my web API controller, because my web app and services are running in same domain

    • Sorry – I don’t follow. For authZ to work you need a ClaimsPrincipal set up, the authZ DI services need be configured etc. Then it should work as expected.

      Maybe ask on the github issue tracker about it.

  12. Andres Romero says:

    I started to use it and i got frustrated. I used to have a custom attribute in MV5 like this

    [ResourceAuthorize(Resource, Operation)]
    public ActionResult [SomeAction]( [Params] )
    {
    …………..
    }

    It checks in the user permissions (from database, claims, or other data stores) if the user has access to perform a certain Operation on a Type of Resource (previously configured in our Security System). The new implementation forces me to code for each Type of Resource, and load the resource. I want to be able to do what i used to do, via an attribute i determine if the user has permissions based on a type of resource and an operation. Is it still possible?

    • I’ve been told that RC2 will have a way to make this scenario easier.

      • Andres Romero says:

        I talked about it with Barry Dorrans from the security team and told me that RC2 will bring AuthPolicyProvider which will make things like this possible. I hope RC2 comes soon!

  13. bob says:

    I agree with your sentiments that the CRUD doesn’t belong in the Claims (and thus the auth token) but that is what I’m doing today because I’m struggling to find a design pattern. My security is user defined and all CRUD privileges are stored in a database. Currently their “rights” are stuffed into the token on authorization. I’m not yet using ASPNET core but trying to model after future patterns – any suggestions? I like the sounds of IPermissionRepo discussed here – https://github.com/aspnet/Security/issues/297

    • see here http://docs.asp.net

      You can use a similar approach in v.current. But you have to build it yourself, which isn’t too hard.

      • bob says:

        Thanks, yes I’ve read all those docs. I just wasn’t really seeing where I’d put the hook in to check the “dynaymic” (database-driven) user security. I guess I’d just use the resource pattern, and make an IAuthorizationService that has a database-backed Repo class like you suggested in your Issue with ASPNET team. The nice thing about putting the CRUD into the token is there is only one database hit, this will add the overhead of an additional query every request – is there a way to avoid this?

      • Andres Romero says:

        We are getting all claims into a cookie once per hour and then in your Action you check for a specific claims to know if a user can make a certain action. Every one hour the cookie gets rehydrated automatically. We don´t do that in all our apps but it is a valid resource.

      • bob says:

        Andres Romero – I have the cookie, and a bearer token to contend with. The security is fine-grained, so there are a lot of claims; both the the cookie and token are rather large and it sucks passing them with every request. I like your every hour idea though that would be an improvement to my current setup where the user must logout for any changes to crud.

  14. “The only thing I don’t like about this approach is, that it pushes you towards using the claims collection as the sole data source for authorization decisions. As we all know, claims describe the identity of the user, and are not a general purpose dumping ground for all sorts of data – e.g. permissions.”

    Sir, what could be better than claims? I want to know that what should be if claims are not appropriate? It is fairly possible if someone has to individually authorize then there is a need for claims. So how we can leave claims?

  15. Did you have sample for using authorization using Web Api in asp.net core rc2

  16. David says:

    Do you have anything on Pluralsight or similar where you can learn more about this? I am still very new to it all and find a great deal of the web tutorials leave large gaps

  17. Matt says:

    Why is this new Claims approach better than Roles? I think I somewhat understand the difference of the two after watching video after video and reading article after article for two days now, but in theory, you could just granulate the roles, couldn’t you? You could have a role for every function you want to do: SalesOnly, SalesOnlySenior, etc? With me just writing that out, I can see how claims is better for individual things, but doesn’t really seem better for things that were traditionally role based?

    The biggest difference I see in this new approach is all the extra code that makes it virtually impossible to understand and put together, at least for people like myself that don’t understand the smoke and mirrors?

    By, impossible to understand, I mean what you wrote is understandable in general. But, when it comes time for the rubber to meet the road, do I want a AuthorizeFilter or an AuthorizationHandler or an AuthorizationRequirement or what? How do you go about something as basic as just creating an admin user type of role… but claims based? There’s literally no code examples out there for that. All examples resort back to the older way of doing things, which we’re not supposed to do now.

    And how do we manage these claims besides writing them into startup.cs or modifying the database manually?

    I’m sure for the seasoned .NET brainiacs, this claims stuff makes perfect sense. But, for the rest of us just trying to get the ball rolling and just add some basic functionality to a basic project, it’s really painful and convoluted…unlike Roles was.

    Anyway, thanks for your article. It’s probably one of the clearest examples I’ve seen. I’m hoping once I get to day three or four or at some point in the future, the light just comes on and I can finally write some code moving in the right direction.

Leave a comment