Hamburglar Hamburglar - 1 month ago 5
ASP.NET (C#) Question

ASP.NET 5 Policy-Based Authorization Handle Not Being Called

Following the docs here I tried to implement a policy-based auth scheme. http://docs.asp.net/en/latest/security/authorization/policies.html#security-authorization-handler-example

I ran into the issue that my Handle method was not being called on my custom AuthorizationHandler. (It does not throw here). It also does inject the dependency currently in the constructor.

Here it the AuthorizationHandler Code.

using WebAPIApplication.Services;
using Microsoft.AspNet.Authorization;

namespace WebAPIApplication.Auth
{
public class TokenAuthHandler : AuthorizationHandler<TokenRequirement>, IAuthorizationRequirement
{
private IAuthService _authService;

public TokenAuthHandler(IAuthService authService)
{
_authService = authService;
}

protected override void Handle(AuthorizationContext context, TokenRequirement requirement)
{
throw new Exception("Handle Reached");
}
}

public class TokenRequirement : IAuthorizationRequirement
{
public TokenRequirement()
{
}
}
}


In Start Up I have

// Authorization
services.AddSingleton<IAuthorizationHandler, TokenAuthHandler>()
.AddAuthorization(options =>
{
options.AddPolicy("ValidToken",
policy => policy.Requirements.Add(new TokenRequirement()));
});


The controller method is

// GET: api/values
[HttpGet, Authorize(Policy="ValidToken")]
public string Get()
{
return "test";
}


Hitting this endpoint returns nothing and there is a warning in the console of

warn: Microsoft.AspNet.Mvc.Controllers.ControllerActionInvoker[0]
Authorization failed for the request at filter 'Microsoft.AspNet.Mvc.Filters.AuthorizeFilter'.


I am able to hit other endpoints that don't have the attribute successfully.

SOS,
Jack

Answer

The answer to this question is alluded to in a comment to adem caglin, so props to him.

The issue is that the AuthorizeFilter is rejecting the request before the AuthorizationHandler is being called. This is because for every use of the Authorize tag MVC adds AuthorizeFilter ahead of the AuthorizationHandler in the pipeline. This AuthorizeFilter checks to see if any of the current users identities are authorized. In my case there were no authorized identities associated with any user so this would always fail.

A solution (which IMO is somewhat hackish) is to insert a peice of middleware that will get executed before any MVC code. This middleware will add a generic authenticated identity to a User (if the user does not already have one).

Consequently the AuthorizeFilter check will pass and the Handle method on the AuthenticationHandler method will be executed and our problem will be solved. The middleware code (which needs to be added to Configure before app.UseMvc(); is called) is as follows

    app.Use(async (context, next) =>
    {
        if (!context.User.Identities.Any(i => i.IsAuthenticated))
        {
            context.User = new ClaimsPrincipal(new GenericIdentity("Unknown"));
        }
        await next.Invoke();
    });

An alternative way to override the AuthorizeFilter is outline here (Override global authorize filter in MVC 6)

Citing the response from here (Asp.Net Core policy based authorization ends with 401 Unauthorized)