Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET Core Authorization Policies: Can't step into the handler?

I have JWT-based claims authentication/ authorization set up in my .NET Core application, which authenticates as expected, but my policy enforcement is not acting as I would expect.

I have a requirements implementation and handler set up as follows:

public class ImpersonationRequirement : IAuthorizationRequirement
{
}

public class ImpersonationHandler : AuthorizationHandler<ImpersonationRequirement>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
        ImpersonationRequirement requirement)
    {
        if (context.User.CanImpersonate()) context.Succeed(requirement);

        return Task.CompletedTask;
    }
}

I have a helper set up like so:

public static bool CanImpersonate(
    this ClaimsPrincipal principal)
{
    var val = principal?.FindFirst(MyClaimTypes.CAN_IMPERSONATE)?.Value;
    return bool.TryParse(val, out var value) && value;
}

public class MyClaimTypes
{
    /// <summary>
    /// Boolean value indicating this user is authorized to impersonate other customer accounts.
    /// </summary>
    public const string CAN_IMPERSONATE = "cim";

    ...

    /// <summary>
    /// Actual name of the user impersonating the current user.
    /// </summary>
    public const string IMPERSONATING_USER = "imp";
}

...off of my Startup.cs, I have the policy defined:

services.AddAuthorization(options =>
{
    options.AddPolicy("Impersonator", policy => policy.Requirements.Add(new ImpersonationRequirement()));
});

...and on my controller, it's written as such:

[Produces("application/json")]
[Authorize(Policy = "Impersonator")]
public class ImpersonationController : Controller
{
    private readonly ILogger _logger;
    private readonly ITokenManagementService _tokenManagementService;
    private readonly UserManager<MyUser> _userManager;

    public ImpersonationController(ITokenManagementService tokenManagementService, ILoggerFactory loggerFactory, UserManager<MyUser> userManager)
    {
        _tokenManagementService = tokenManagementService;
        _userManager = userManager;
        _logger = loggerFactory.CreateLogger<ImpersonationController>();
    }

    [HttpPost]
    [Route("~/api/impersonation/token")]
    [ProducesResponseType(typeof(AuthenticationResponse), 200)]
    [ProducesResponseType(typeof(Exception), 500)]
    public async Task<IActionResult> Impersonate([FromBody] string userNameToImpersonate)
    {
        try
        {
            var impersonated = await _userManager.FindByNameAsync(userNameToImpersonate);
            if (impersonated == null) throw new EntityNotFoundException($"Unable to find user '{userNameToImpersonate}' in the data store.");
            var actualUserId = User.UserId();
            var token = await _tokenManagementService.GenerateJwt(impersonated.Id, actualUserId);
            var refresh = await _tokenManagementService.GenerateRefreshToken(impersonated.Id, actualUserId);
            var response = new AuthenticationResponse {AuthenticationToken = token, RefreshToken = refresh};
            return Ok(response);
        }
        catch (Exception ex)
        {
            return new OopsResult(ex);
        }
    }
}

If I run this with the AuthorizeAttribute commented out, I can take a look at the user's claims, and the "cim: true" is in the claims enumeration, but if I run it with the AuthorizeAttribute enabled, I get a 403 Forbidden error.

I tried putting a breakpoint on the line in the ImpersonationHandler:

if (context.User.CanImpersonate()) context.Succeed(requirement);

...but the debugger never stops here, so I don't know what the problem is. Can someone educate me as to what I'm doing wrong?

like image 851
Jeremy Holovacs Avatar asked Apr 06 '18 14:04

Jeremy Holovacs


People also ask

What is AddAuthorizationCore?

AddAuthorizationCore(IServiceCollection)Adds authorization services to the specified IServiceCollection. C# Copy. public static Microsoft.Extensions.DependencyInjection.

What is IAuthorizationRequirement?

IAuthorizationRequirement is a marker service with no methods, and the mechanism for tracking whether authorization is successful.

How does ASP NET core authentication work?

In ASP.NET Core, authentication is handled by the authentication service, IAuthenticationService, which is used by authentication middleware. The authentication service uses registered authentication handlers to complete authentication-related actions.


1 Answers

It seems you forgot to register your ImpersonationHandler in DI container (which is indeed easy to forget):

services.AddSingleton<IAuthorizationHandler, ImpersonationHandler>();

Asp.net resolves all such handlers from container and tries to match for specific requirement. Since no such handler is registered - nothing sets context.Succeed and whole authorization fails.

like image 118
Evk Avatar answered Sep 22 '22 22:09

Evk