I am trying to get a dependency injected into the constructor of a custom authorization handler, but the AddAuthorization in asp.net is making it difficult.
Handler:
class MyHandler : AuthorizationHandler<MyRequirement>
{
readonly IDependent dependency;
public UserExistsHandler(IDependent dependency)
{
this.dependency = dependency;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, MyRequirement requirement)
{
context.Succeed(requirement);
}
}
Program.cs
builder.Services.AddSingleton<IAuthorizationHandler, MyHandler>();
builder.Services.AddAuthorization(config =>
{
config.AddPolicy("MyPolicy", policy =>
{
// how?
policy.AddRequirements(new )
});
});
According to official documentation this should be possible:
https://learn.microsoft.com/en-us/aspnet/core/security/authorization/dependencyinjection?view=aspnetcore-6.0
However, the signature for AddRequirements is not generic and requires me to pass an actual instance of the handler which I cannot do because I have no reference to the IServiceProvider in the config delegate.
https://github.com/dotnet/aspnetcore/blob/4faa84c9ddf8c9e9cc9e5b43ca15f090037c4b68/src/Security/Authorization/Core/src/AuthorizationPolicyBuilder.cs#L73
How do I register the handler without having to create a new instance to be registered which defeats the purpose of the DI I am trying to do?
It's not the handler that you need to pass to AddRequirements, but the an instance of MyRequirement.
builder.Services.AddAuthorization(config =>
{
config.AddPolicy("MyPolicy", policy =>
{
policy.AddRequirements(new MyRequirement());
});
});
Related
I've created a custom authorize filter which looks like this:
public class BearerTokenAuthorizeFilter : AuthorizeFilter
{
public override async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
await base.OnAuthorizationAsync(context);
if (context.Result is ChallengeResult)
{
// Then return a problem detail
ObjectResult result = new ObjectResult(new ProblemDetails
{
Type = ProblemDetailsTypes.Unauthorized,
Title = ReasonPhrases.GetReasonPhrase(StatusCodes.Status401Unauthorized),
Status = StatusCodes.Status401Unauthorized,
Detail = ProblemDetailsDescriptions.Unauthorized
});
result.ContentTypes.Add(new MediaTypeHeaderValue(new Microsoft.Extensions.Primitives.StringSegment("application/problem+json")));
context.Result = result;
await context.HttpContext.ChallengeAsync();
}
else if (context.Result is ForbidResult)
{
context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
await context.HttpContext.ForbidAsync();
}
}
}
I am registering this filter like this:
services.AddMvcCore(options =>
{
options.Filters.Add<BearerTokenAuthorizeFilter>();
});
I have set the default authentication to be 'Bearer':
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
I have added Authorize attribute on the controller. Whenever I send an unauthorized request to the endpoint my custom filter is never called and I have no idea why? My goal is to return problem details if the request is unauthorized to provide a little bit more information to the consumer than just the status code. Why is my filter not being called?
Try implement IAuthorizationFilter or IAsyncAuthorizationFilter instead of AuthorizeFilter. It work for me. Also I noticed that GetFilter(..) method returns AuthorizeFilter instance directly in AuthorizationApplicationModelProvider when filter class implements AuthorizeFilter. But when filter implements IAuthorizationFilter or IAsyncAuthorizationFilter this method being not called I think that is issue in ASP NET
I have ended up implementing my own IControllerModelConvention class which looks like this:
public class BearerTokenAuthorizeConvention : IControllerModelConvention
{
private AuthorizationPolicy _policy;
public BearerTokenAuthorizeConvention(AuthorizationPolicy policy)
{
_policy = policy;
}
public void Apply(ControllerModel controller)
{
if (controller.Filters.OfType<BearerTokenAuthorizeFilter>().FirstOrDefault() == null)
{
//default policy only used when there is no authorize filter in the controller
controller.Filters.Add(new BearerTokenAuthorizeFilter(_policy));
}
}
}
This will be executed once per controller. I then registered this convention like this:
// Configure application filters and conventions
services.Configure<MvcOptions>(options =>
{
AuthorizationPolicy defaultPolicy = new AuthorizationOptions().DefaultPolicy;
options.Conventions.Add(new BearerTokenAuthorizeConvention(defaultPolicy));
});
At this point every controller I have will be tagged with this custom filter which will call base implementation of AuthorizeFilter. The reason why I wanted to derive from AuthorizeFilter was because I wanted to call the default implementation of Authorize and then handle failed response on my own. I thought I could accomplish this very functionality and somehow still be able to only use Authorize attribute. This doesn't seem to be possible. Unless it is an I'm missing something?
I am trying setup an authoriztion policy that I can use to decorate actions in API Controllers in .net core 3.1. I have been following these examples :
https://learn.microsoft.com/en-us/aspnet/core/security/authorization/resourcebased?view=aspnetcore-3.1
If i have an API action decorated like below my code does not hit the handlerequirementAsync method of the handler and I get a 403 Forbidden response from swagger. If i remove the document model from the handler/requirement it does work. Am I doing something wrong or is this not supported for api requests?
here is the other relevant code :
public class DocumentAuthorizationHandler :
AuthorizationHandler<SameAuthorRequirement, Document>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
SameAuthorRequirement requirement,
Document resource)
{
if (context.User.Identity?.Name == resource.Author)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
public class SameAuthorRequirement : IAuthorizationRequirement { }
[Authorize(Policy = "EditPolicy")]
public async Task<FileResult> RetreiveFile([FromRoute]Document model)
{
}
services.AddAuthorization(options =>
{
options.AddPolicy("EditPolicy", policy =>
policy.Requirements.Add(new SameAuthorRequirement()));
});
services.AddSingleton<IAuthorizationHandler, DocumentAuthorizationHandler>();
You should have to inject IAuthorizationService in the controller constructor
public class AbcController : Controller
{
private readonly IAuthorizationService _authorizationService;
public AbcController(IAuthorizationService authorizationService)
{
_authorizationService = authorizationService;
}
// No need to add this [Authorize(Policy = "EditPolicy")]
public async Task<FileResult> RetreiveFile([FromRoute]Document model)
{
//add this below line which shall call the handler
var authorizationResult = await _authorizationService.AuthorizeAsync(User, model, "EditPolicy");
}
Consider the following code in the ConfigureServices method of the Startup class -
services.AddTransient<IAuthorizationHandler, BlockUsersHandler>();
services.AddTransient<IAuthorizationHandler, BlockClaimHandler>();
services.AddAuthorization(option =>
{
option.AddPolicy("NotHacker", policy =>
{
policy.AddRequirements(new BlockUsersRequirement("Hacker"));
});
option.AddPolicy("NotThatClaim", policy =>
{
policy.AddRequirements(new BlockClaimRequirement(new Claim("ThatClaimType", "ThatClaim")));
});
});
and these are the custom class implementations -
public class BlockUsersRequirement : IAuthorizationRequirement
{
// Code goes here
}
public class BlockUsersHandler : AuthorizationHandler<BlockUsersRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, BlockUsersRequirement requirement)
{
// Code goes here
}
}
public class BlockClaimRequirement : IAuthorizationRequirement
{
// Code goes here
}
public class BlockClaimHandler : AuthorizationHandler<BlockClaimRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, BlockClaimRequirement requirement)
{
// Code goes here
}
}
My understanding was that whenever a dependency on a service is faced, the built-in dependency resolver provides the concrete implementation registered for that service and if I register multiple implementation of a service, then the last registration will take effect.
In the code above, two implementations are registered for IAuthorizationHandler and the two authorization policies are working fine with that.
So, how is the dependency resolver deciding when to select which implementation? And based on what?
EDIT - 2019.07.28
So, as #Martin answered below, looks like the dependency resolver can infer the implementation from the IAuthorizationRequirement in the AuthorizationHandler<TRequirement>, from which the Handler implementations are deriving.
But you actually can create a Handler class by directly implementing the IAuthorizationHandler interface without deriving from AuthorizationHandler<TRequirement> -
public class DeletePermissionRequirement : IAuthorizationRequirement
{
// Nothing here
}
public class DeletePermissionHandler : IAuthorizationHandler
{
public Task HandleAsync(AuthorizationHandlerContext context)
{
// Code goes here
}
}
So, now there is no IAuthorizationRequirement in the Handler's signature to infer from.
Also, you can add multiple Handler implementations for a single Requirement -
public class BuildingEntryRequirement : IAuthorizationRequirement
{
// Nothing here
}
public class BadgeEntryHandler : AuthorizationHandler<BuildingEntryRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, BuildingEntryRequirement requirement)
{
// Code goes here
}
}
public class TemporaryPassHandler : AuthorizationHandler<BuildingEntryRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, BuildingEntryRequirement requirement)
{
// Code goes here
}
}
Taking the these new implementations into account the code in the ConfigureServices method looks like -
services.AddTransient<IAuthorizationHandler, BlockUsersHandler>();
services.AddTransient<IAuthorizationHandler, BlockClaimHandler>();
services.AddTransient<IAuthorizationHandler, DeletePermissionHandler>();
services.AddTransient<IAuthorizationHandler, BadgeEntryHandler>();
services.AddTransient<IAuthorizationHandler, TemporaryPassHandler>();
services.AddAuthorization(option =>
{
option.AddPolicy("NotHacker", policy =>
{
policy.AddRequirements(new BlockUsersRequirement("Hacker"));
});
option.AddPolicy("NotThatClaim", policy =>
{
policy.AddRequirements(new BlockClaimRequirement(new Claim("ThatClaimType", "ThatClaim")));
});
option.AddPolicy("CanDelete", policy =>
{
policy.AddRequirements(new DeletePermissionRequirement());
});
option.AddPolicy("BadgeEntry", policy =>
{
policy.AddRequirements(new BuildingEntryRequirement());
});
});
and, of course, all the authorization policies are working fine.
So again, how the dependency resolver is selecting the right implementation?
It is using the type of the requirement to decide which handler to use.
There can be more simultaneous authorization handlers that differ in type of the requirement.
It is possible to check more requirements in one policy.
Also when the authorization service is called, it picks the right handler:
IAuthorizationService _authorizationService; // injected
_authorizationService.AuthorizeAsync(User, resourceId, new MyAuthorizationRequirement(UserAccessScope.Account, resourceId, requiredRole));
Update:
The default behavior is
for a given AuthorizationHandlerContext all registered IAuthorizationHandler handlers are evaluated
for each of these handlers the method HandleAsync is called
a handler that derives from the abstract AuthorizationHandler<TRequirement> class implements the method HandleAsync this way:
public virtual async Task HandleAsync(AuthorizationHandlerContext context)
{
foreach (var req in context.Requirements.OfType<TRequirement>())
{
await HandleRequirementAsync(context, req);
}
}
It means the handler filters the requirements by type. It also means a handler that does not derive from the abstract class AuthorizationHandler<TRequirement> has its own implementation of the HandleAsync method.
The difference between an authorization handler that does inherit from the abstract class AuthorizationHandler<TRequirement> and one that doesn't boils down to how the HandleAsync method of the interface IAuthorizationHandler is implemented. AuthorizationHandler<TRequirement> has a default implementation described above, the implementor of the generic interface IAuthorizationHandler needs to supply its own implementation.
The answer to the second part concerning multiple Handler implementations for a single Requirement is, all handlers which have requirement of the given type will be evaluated, and if any one of them succeeds and none of them explicitly fails (Fail method has been called on the context) then the operation will be authorized.
ASP .NET Core dependency injection container can resolve to a single implementation per Interface and can resolve to all registered implementations based on the signature that's resolved.
Signature Interface is resolved to a single implementation - last one registered.
Signature IEnumerable<Interface> is resolved to all registered implementations.
I assume that IAuthorizationHandler is resolved using IEnumerable<IAuthorizationHandler> and therefore all implementations are created.
In my asp.net core 2.0 web app, I've got a custom ISecurityTokenValidator which validates tokens.
It depends on a repository to do a db lookup - the repository itself is setup as a scoped dependency:
services.AddScoped<IMyRepository>(MyRepository);
Now the funkiness comes about because of the way the ISecurityTokenValidator is setup.
It's added in ConfigureServices:
.AddJwtBearer(options =>
{
options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(new MyTokenValidator(services.BuildServiceProvider()));
})
This is how it looks:
public class MyTokenValidator : ISecurityTokenValidator
{
private readonly IServiceProvider _serviceProvider;
public MyTokenValidator(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public bool CanReadToken(string securityToken) => true;
public ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters,
out SecurityToken validatedToken)
{
var serviceScopeFactory = _serviceProvider.GetRequiredService<IServiceScopeFactory>();
using (var scope = serviceScopeFactory.CreateScope())
{
var myRepository = scope.ServiceProvider.GetService<IMyRepository>();
var principalFactory = scope.ServiceProvider.GetService<IUserClaimsPrincipalFactory<User>>();
// Use the repo....
}
}
}
Now, because the IsecurityTokenProvider is only instantiated once, it's effectively a singleton. When I use the service provider to ask for a IMyRepository I was finding that I was always received the same object - there is no new scope as far as it was concerned, because it's in a singleton class.
To get round that, you'll see in the code above Ive had to manually force a new scope every time the token validator is called. Is this really the only way to resolve this, it seems like I'm hacking around to make it work here...
Old question but the best way I have found to solve this problem is to use IPostConfigureOptions<JwtBearerOptions> to configure SecurityTokenValidators.
First register the JWT bearer and options
services.AddAuthentication(options =>
{
...
}).AddJwtBearer(AuthenticateScheme, options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
...
};
});
Then register a custom implementation of IPostConfigureOptions<JwtBearerOptions>
services.AddSingleton<IPostConfigureOptions<JwtBearerOptions>, CustomJwtBearerOptionsPostConfigureOptions>();
And register a custom implementation of ISecurityTokenValidator
services.AddSingleton<MyCustomSecurityTokenValidator>();
CustomJwtBearerOptionsPostConfigureOptions could look something like:
public class CustomJwtBearerOptionsPostConfigureOptions : IPostConfigureOptions<JwtBearerOptions>
{
private readonly MyCustomSecurityTokenValidator _tokenValidator; //example dependancy
public CustomJwtBearerOptionsPostConfigureOptions(MyCustomSecurityTokenValidator tokenValidator)
{
_tokenValidator = tokenValidator;
}
public void PostConfigure(string name, JwtBearerOptions options)
{
options.SecurityTokenValidators.Clear();
options.SecurityTokenValidators.Add(_tokenValidator);
}
}
Now options.SecurityTokenValidators is configured by CustomJwtBearerOptionsPostConfigureOptions which is instantiated by dependency injection and can pass on the relevant decencies.
I am working on a website where I need to authorize the user through a service. I have managed to get windows authentication working if I use the AuthorizeAttribute (User.Identities will be set). My plan is to create a custom middleware that sets the roles/claims for the user but context.User is not set in the middleware. User.Identities will also not be set in the controllers where I don't add the AuthorizeAttribute.
My goal is to write a middleware that gets the windows username and calls a service with the username to get the roles the user has access to and then set the roles or claims for the user.
public class RoleMiddleware
{
private readonly RequestDelegate _next;
public RoleMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
if (!rolesSet)
{
var result = _service.GetRoles(context.User.Identity.Name);
//set roles
//set claims
}
await _next.Invoke(context);
}
}
Would a middleware be the correct place to do this and what do I need to do to get access to the username in the same way as I do when I use the AuthorizeAttribute in a controller?
In my opinion that's not the right way to do it. ASP.NET Identity provide rich set of classes which you can override and extend to fit your requirements.
If you want to inject roles bases on some custom service then you should override RoleStore (and maybe RoleManager too) and inject there your custom roles.
It will be also worth to take a look here: Using Role Claims in ASP.NET Identity Core
I solved it by using requirements
public class CustomFunctionRequirement : IAuthorizationRequirement
{
public CustomFunctionRequirement(string function)
{
Function = function;
}
public string Function { get; }
}
The handler
public class CustomFunctionHandler : AuthorizationHandler<CustomFunctionRequirement>
{
private readonly Service _service;
public CustomFunctionHandler(Service service)
{
_service = service;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomFunctionRequirement requirement)
{
var functions = _service.GetFunctions(context.User.Identity.Name);
if (functions.Any(x => x == requirement.Function))
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
Setup in ConfigureServices in Startup
services.AddMvc(
config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});
services.AddAuthorization(
options =>
{
options.AddPolicy("User", policy => policy.Requirements.Add(new CustomRequirement("User")));
});
I can now in my controller specify the requirement by adding the authorize attribute [Authorize(Policy = "User")].