authorization iii

7
Authorization Part III Custom Policy-Based Authorization Both the role authorization and claims authorization make use of a need, a handler for the requirement and a per-configured policy. They allow you to express authorization access in code, allowing a richer, reusable, and easily testable authorization structure. An authorization policy is made up of one or more needs and registered at application startup as part of the Authorization service configuration, in ConfigureServices in the Startup.cs file system. public void ConfigureServices(IServiceCollection services) { services.AddMvc(); services.AddAuthorization(options =>

Upload: sonia-merchant

Post on 21-Jan-2017

21 views

Category:

Education


0 download

TRANSCRIPT

Authorization

Part III

Custom Policy-Based Authorization

Both the role authorization and claims authorization make use of a need, a handler for the requirement and a per-configured policy.

They allow you to express authorization access in code, allowing a richer, reusable, and easily testable authorization structure.

An authorization policy is made up of one or more needs and registered at application startup as part of the Authorization service configuration, in ConfigureServices in the Startup.cs file system.

public void ConfigureServices(IServiceCollection services)

{

services.AddMvc();

services.AddAuthorization(options =>

{

options.AddPolicy("Over21",

policy => policy.Requirements.Add(new MinimumAgeRequirement(21)));

}

});

Here you see an “Over21” policy is created with a single requirement of a minimum age, which is passed as a requirement.

Policies are applied using the Authorize feature by specifying the policy name, e.g.

[Authorize(Policy="Over21")]

public class AlcoholPurchaseRequirementsController : Controller

{

public ActionResult Login()

{

}

public ActionResult Logout()

{

}

}

Requirements

An authorization requirement is a sum of data parameters that a policy can use to evaluate the current user principal. In the Minimum Age policy, the requirement is of a single parameter. A requirement must implement IAuthorizationRequirement. This is a void, marker interface. The criteria of minimum age requirement might be implemented as follows;

public class MinimumAgeRequirement : IAuthorizationRequirement

{

public MinimumAgeRequirement(int age)

{

MinimumAge = age;

}

protected int MinimumAge { get; set; }

}

A requirement doesn’t need to have data or properties.

Authorization Handlers

This is responsible for the assay of any properties of requirement. The authorization handler must assay them against a provided AuthorizationContext to finalize if authorization is allowed. A requirement can have many handlers. Handlers must inherit AuthorizationHandler<T> where the alphabet T is the need it handles.

The minimum age handler might look like this:

public class MinimumAgeHandler : AuthorizationHandler<MinimumAgeRequirement>

{

protected override Task HandleRequirementAsync(AuthorizationContext context, MinimumAgeRequirement requirement)

{

if (!context.User.HasClaim(c => c.Type == ClaimTypes.DateOfBirth &&

c.Issuer == "http://contoso.com"))

{

return Task.FromResult(0);

}

var dateOfBirth = Convert.ToDateTime(context.User.FindFirst(

c => c.Type == ClaimTypes.DateOfBirth && c.Issuer == "http://contoso.com").Value);

int calculatedAge = DateTime.Today.Year - dateOfBirth.Year;

if (dateOfBirth > DateTime.Today.AddYears(-calculatedAge))

{

calculatedAge--;

}

if (calculatedAge >= requirement.MinimumAge)

{

context.Succeed(requirement);

}

return Task.FromResult(0);

}

}

In the code above let's first see if the current user principal has a DOB claim which has been issued by an Issuer we could know and trust. If the claim is missing we can’t authorize so we return. If we have a claim, we find out how old the user is, and if they meet the minimum age criteria then the authorizationis successful. Once it is a success we call context.Succeed() passing in the requirement.

Handlers must be listed in the services collection during configuration, for example;

public void ConfigureServices(IServiceCollection services)

{

services.AddMvc();

services.AddAuthorization(options =>

{

options.AddPolicy("Over21",

policy => policy.Requirements.Add(new MinimumAgeRequirement(21)));

});

services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();

}

Each handler is added to the services collection by using services.AddSingleton<IAuthorizationHandler, YourHandlerClass>(); passing in your handler class.

You can see in the handler example that the Handle() method has no return value, so how do we indicate success and failure.

A handler depicts success by calling context.Succeed passing the need that has been successfully assayed.

To guarantee failure even if other handlers for a requirement succeed, refer context.Fail.

Why would I want many handlers for a requirement?

In cases where you want the assay on an OR basis, you use multiple handlers for only one requirement.E.g. , Microsoft has doors which open with key cards only. If you leave your key card at home the responsible authority prints a temporary sticker and opens the door for you. In this case, you have a single requirement, EnterBuilding, but many handlers, each one examining a single requirement.

public class EnterBuildingRequirement : IAuthorizationRequirement

{

}

public class BadgeEntryHandler : AuthorizationHandler<EnterBuildingRequirement>

{

protected override Task HandleRequirementAsync(AuthorizationContext context, EnterBuildingRequirement requirement)

{

if (context.User.HasClaim(c => c.Type == ClaimTypes.BadgeId &&

c.Issuer == "http://microsoftsecurity"))

{

context.Succeed(requirement);

return Task.FromResult(0);

}

}

}

public class HasTemporaryStickerHandler : AuthorizationHandler<EnterBuildingRequirement>

{

protected override Task HandleRequirementAsync(AuthorizationContext context, EnterBuildingRequirement requirement)

{

if (context.User.HasClaim(c => c.Type == ClaimTypes.TemporaryBadgeId &&

c.Issuer == "https://microsoftsecurity"))

{

// We'd also check the expiry date on the sticker.

context.Succeed(requirement);

return Task.FromResult(0);

}

}

}

Now, if both handlers are registered when a policy assays the EnterBuildingRequirement if either handler does succeed the policy evaluation will succeed.

Using a function to fulfill a policy

There may be occasions where satisfying a policy is simple to express in code. It is possible to simply supply a Func<AuthorizationHandlerContext, bool> when configuring the policy with the RequireAssertion policy builder.

E.g. the previous BadgeEntryHandler could be again written as follows;

services.AddAuthorization(options =>

{

options.AddPolicy("BadgeEntry",

policy => policy.RequireAssertion(context =>

context.User.HasClaim(c =>

(c.Type == ClaimTypes.BadgeId ||

c.Type == ClaimTypes.TemporaryBadgeId)

&& c.Issuer == "https://microsoftsecurity"));

}));

}

}

Accessing MVC Request the context In Handlers

You must implement the Handle method which has two contexts, an AuthorizationContext and the Requirement you are handling. Frameworks such as MVC or Jabber are free to join any object to the Resource property on the AuthorizationContext to pass through extra information.

If you want to improve your skill set in ASP.Net and optimize yourself in .NET training, then our CRBTech Solutions would be of great support for you. Join us with our scientifically designed program of ASP.Net course.

Stay connected to CRB Tech reviews for more technical optimization and other resources.