Wednesday, March 14, 2018

Asp.Net Core 2 policy-based authorization confusion

I am writing an application that add a new interface to a legacy, Windows application. I'm having difficultly getting policy-based authorization working.

I have a route, /Drivers/Details/{id} that I need to protect. Only the current User may access their driver record. An Operator may access any Driver's record. A User can be a Driver, an Operator, or both.

I'm trying to use a Role and a Policy to protect the DriversController's Details action:

[Authorize(Roles = "Operators",Policy = "UserIsDriver")] public async Task<IActionResult> Details(int? id) { ... } 

Unfortunately, both Operators and the specific user/driver are being denied access to the action.

I created a policy in Startup.cs:

public void ConfigureServices(IServiceCollection services) { ... services.AddMvc(); // authorization policies & requirements services.AddAuthorization(options => { options.AddPolicy("UserIsDriver", policy => policy.Requirements.Add(new UserIsDriverRequirement())); }); // Authorization handlers services.AddSingleton<IAuthorizationHandler, UserIsDriverAuthorizationHandler>(); ... } 

I defined a requirement and handler for the 'UserIsDriver' policy:

// requirement class public class UserIsDriverRequirement : IAuthorizationRequirement { } // handler class public class UserIsDriverAuthorizationHandler : AuthorizationHandler<UserIsDriverRequirement, Driver> { protected override Task HandleRequirementAsync( AuthorizationHandlerContext context, UserIsDriverRequirement requirement, Driver resource ) { if (context.User == null || resource == null) { return Task.CompletedTask; } string email = context.User.FindFirstValue(ClaimTypes.Email); // compare Driver to User if (resource.EmailAddress == email) { context.Succeed(requirement); } return Task.CompletedTask; } } 

In CredentialController's Create action, I assign roles:

// retrieve user record from DB ... // create identity var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme); // add claims identity.AddClaim(new Claim(ClaimTypes.Name, user.Name)); identity.AddClaim(new Claim(ClaimTypes.Email,user.EmailAddress)); // add driver role if (user.DriverID != null) { identity.AddClaim(new Claim(ClaimTypes.Role, Constants.DriversRole, ClaimValueTypes.String)); } // add operator role if (user.OperatorID != null) { identity.AddClaim(new Claim(ClaimTypes.Role, Constants.OperatorsRole, ClaimValueTypes.String)); } 

Maybe I shouldn't be decorating the Details action with roles and policies, but rather doing the authentication in code:

var isAuthorized = await _authorizationService.AuthorizeAsync(User, driver, "UserIsDriver"); if (!isAuthorized.Succeeded) { return new ChallengeResult(); } else if (User.Identity.IsAuthenticated) { return new ForbidResult(); } 

But this won't authorize an operator. Do I need a second policy?

Any assistance would be greatly appreciated.

Asp.Net Core 2 policy-based authorization confusion Click here
  • Blogger Comment
  • Facebook Comment

0 comments:

Post a Comment

The webdev Team