Authorization now includes code configured policy support. #22

Closed
blowdart opened this Issue May 8, 2015 · 15 comments

Projects

None yet
@blowdart
Member
blowdart commented May 8, 2015

ASP.NET authorization now supports code based policies. We provide implementations to support claims based authorization and the ability to express your own policies in code. An authorization policy must contain one or more requirements.

Policy configuration is done within ConfigureServices(...) within Startup.cs.

A simple policy to check for the presence of a claim would be configured as follows

services.ConfigureAuthorization(options =>
{
    options.AddPolicy("MustBeGroot", policy => policy.RequireClaim("IAmGroot"));
}

and would be applied as [Authorize(Policy="MustBeGroot")].

You can also specify a list of comma separated values as part of the claim requirement, for example

options.AddPolicy("MustBeGroot", policy => policy.RequireClaim("Permissions", "Read,Update"));

which would pass authorization if the Permissions claim had a value or either Read or Update.

A more complicated requirement would involve implementing IAuthorizationRequirement and an AuthorizationHandler. For example if your identity had a DateOfBirth claim and you wanted to implement a minimum age requirement it could look like

public class MinimumAgeRequirement : AuthorizationHandler<MinimumAgeRequirement>, IAuthorizationRequirement
{
    public MinimumAgeRequirement(int age)
    {
        MinimumAge = age;
    }

    protected int MinimumAge { get; set; }

    public override void Handle(AuthorizationContext context, MinimumAgeRequirement requirement)
    {
        if (!context.User.HasClaim(c => c.Type == ClaimTypes.DateOfBirth))
        {
            return;
        }

        var dateOfBirth = Convert.ToDateTime(context.User.FindFirst(c => c.Type == ClaimTypes.DateOfBirth).Value);

        int calculatedAge = DateTime.Today.Year - dateOfBirth.Year;
        if (dateOfBirth > DateTime.Today.AddYears(-calculatedAge))
        {
            calculatedAge--;
        }

        if (calculatedAge >= MinimumAge)
        {
            context.Succeed(requirement);
        }
    }
}

You could then configure it

options.AddPolicy("Over21", 
    policy => policy.Requirements.Add(new Authorization.MinimumAgeRequirement(21)));

and apply it via [Authorize(Policy="Over21")].

Finally you can use policy to limit the authentication schemes checked during authorization, for example

options.AddPolicy("WebApi", policy =>
{
     policy.ActiveAuthenticationSchemes.Add("Bearer");
     policy.RequireAuthenticatedUser();
});

would only allow requests which provide an identity to Bearer middleware to access the resource behind them.

@blowdart blowdart added this to the 1.0.0-beta4 milestone May 8, 2015
@timmydo
timmydo commented May 8, 2015

you mean [Authorize(Policy="MustBeGroot")]?

@blowdart
Member
blowdart commented May 8, 2015

I did. Corrected. Thanks. More formal documentation will be coming in the next few weeks.

@sandorfr
sandorfr commented May 9, 2015

You mentioned that a policy can contain one or more requirement, but I'm under the impression that it is a must.

@blowdart
Member
blowdart commented May 9, 2015

And this is why I don't do off the cuff documentation, corrected, thank you.

@leastprivilege

How do I set a global authZ policy? e.g. all controller require an authenticated user

@aggieben
aggieben commented May 9, 2015

@leastprivilege I'm doing it like this:

var policyBuilder = new AuthorizationPolicyBuilder(OAuth1AuthenticationDefaults.AuthenticationScheme);
var policy = policyBuilder.Build();

services.ConfigureMvc(options => {
   options.Filters.Add(new AuthorizeFilter(policy));
});
@leastprivilege

This nulls the Identity property on User if the request is anonymous. So this is either a bug - or that is not the right way of installing a global authZ policy.

@crozone
crozone commented Aug 21, 2015

How can you manually check whether a User meets a given AuthorizationPolicy, outside of the AuthorizeAttribute?

Given that AuthorizationOptions can be injected, is there something like bool allowed = AuthorizationOptions.GetPolicy("SomePolicy").Evaluate((ClaimsPrincipal)User) ?

@damccull

Is it possible for a controller/action to use multiple policies? Like "Bearer" and "MinimumAgeRequirement"?

@XplMarcel

If an Authorize attribute on a Controller has Roles ( [Authorize(Roles = "MyRole"] ), the RolesAuthorizationRequirement gets added automatically to the defaultPolicy.
Would it be possible to replace that requirement with my own RolesRequirement class ?

@Eilon
Member
Eilon commented Sep 29, 2015

@XplMarcel please log an issue in the https://github.com/aspnet/Security/ repo.

@khellang

Can we please lock this issue and refer to https://github.com/aspnet/Security/ instead?

@MaximRouiller

Is it possible to add a discussion thread and lock this?

@blowdart
Member

This is 9 months old, long before the lock and discuss. I'd hope discussion is done now, so locking.

@blowdart blowdart closed this Feb 15, 2016
@blowdart blowdart locked and limited conversation to collaborators Feb 15, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.