I am trying to understand the ASP.NET policy-based authorization mechanism, and I understood that I need to do the following:
Set up a policy
Assign requirements to that policy
Define authorization handlers to these requirements which perform the actual validation (And return whether the requirements were fullfilled or not)
Add the authorization handlers to the dependency injection mechanism
However, reading the ASP.NET documentation, I understand I might need to set up an IAuthorizationService as well. I failed to understand why that is needed for from the ASP.NET documentation.
Do I have to set one up? What should it do? Is that an alternative to the policy and authorization handlers I am setting up or a required addition to them?
U can override IAuthorizationService to take control of full authorization logic in your application.
By default, IAuthorizationService is responsible for validation of Policy- Claim- or Role-based ruled, defined in AuthorizationOptions.
IAuthorizationService is usually being invoked in IAsyncAuthorizationFilter (which MVC adds automatically once u mark Controller or Action with [Authorize] attribute).
Related
I want to provide additional query string parameter authentication for some actions in some controllers. I want it to bypass [Authorize] but to use it if this custom query string authentication fails.
I've tried using IAuthorizationFilter with IOrderedFilter with Order = 0 but it seems in .net 3.1+ it's not working anymore.
Basically I want my filter to check for query string key, if this authentication fails it would pass the workflow to [Authorize] filter.
BUT if my custom Authentication filter would succeed - it should disable [Authorize] and go right to the action.
The best option I discovered is to use Policies. In Policy I can check my custom authentication and if it does not work check if (context.User.Identity.IsAuthenticated) for default auth.
For your information. Custom filters did not work. IOverrideAuthorizationFilter is NOT part of asp.net core 3.1+, so don't go there.
Custom middleware does not give you opportunity to override authentication filters.
Best option is to use Policy. On this matter official Microsoft documentation does explanation well.
ASP.NET has the [Allow Anonymous] attribute which allows you to bypass authorization on a specific endpoint. I'm wondering if there's a common way of enabling specific authentication schemes on an endpoint by endpoint basis.
Imagine you wanted to support different schemes like a Basic scheme and a Bearer scheme and so on. But you didn't want to support all schemes on all endpoints. It seems like a convenient way to do that would be to create attributes like [BasicAuth] and [BearerAuth] so you could just annotate the specific endpoints you want to enable. Looking at how AuhtorizationAttributes work, however, it seems like they behave like a logical AND rather than a logical OR.
For example, if I annotated an endpoint with both [BasicAuth] and [BearerAuth] and one returns False on IsAuthorized the whole thing would fail. This makes me think I'm either looking in the wrong place or have an uncommon use-case.
Am I looking in the wrong direction?
AuthorizationAttribute supports different kind of authorizations. It can be used to support Policies or Roles. If you want an OR kind of logic you can use the authorization attribute with a comma separated string for roles. That will let your endpoint accessible by those roles.
Use it like this for OR logic:
[Authorize(Roles = "HRManager,Finance")]
public class SalaryController : Controller
{
}
For AND logic
[Authorize(Roles = "PowerUser")]
[Authorize(Roles = "ControlPanelUser")]
public class ControlPanelController : Controller
{
}
Source is Role-based authorization
I would recommend reading through the whole Authorization documentation.
Let's say I have to integrate with a legacy enterprise system which maintains users. Assume this enterprise system provides a C# SDK with two methods as follows:
Authentication:
sdk.Authenticate("Region", "Username", "Password")
Note that Region is an additional parameter selected by the user at login. So I need to be able to read this custom parameter in addition to the user credentials too. (Yes login would be interactive).
Profile Retrieval:
sdk.GetProfile(UserId)
I want to use IdentityServer to generate tokens in the usual manner but use these two methods to implement custom authentication and profile retrieval.
I can see that extending the IProfileService I should be able to integrate profile retrieval and population of custom claims. However I see the following multiple extensibility points in the docs but not sure what the best way would be;
Quick Start UI's Account Controller's Login(LoginInputModel model, string button) method: I should be able to place the sdk.Authenticate("Region", "Username", "Password") logic here and just call _signInManager.SignInAsync to sign in the user. But it does not feel as if I'm directly extending IdentityServer4 to add support for another custom authentication provider.
IExtensionGrantValidator:
This answer and IdentityServer Docs explain a way to do a custom grant which I should be able to use to call sdk.Authenticate("Region", "Username", "Password"). But this would mean I'd be using a custom grant type. I need to be able to support existing grant types such as Hybrid. I see support for custom parameters via context parameter in the ValidateAsync(ExtensionGrantValidationContext context) method
IResourceOwnerPasswordValidator:
This IdentityServer doc explains how to implement a custom password validator for the Resource Owner flow. But I need to be able to support existing grant types such as Hybrid. I see support for custom parameters via context parameter in the ValidateAsync(ResourceOwnerPasswordValidationContext context) method
External Authenticators:
This IdentityServer doc explains how to add external authenticators. But I see no .AddCustom method for non-standard authenticators. I only see support for popular authenticators such as Google.
What am I missing?
I chose to go with the first option mentioned in the question which is: Quick Start UI's Account Controller's Login(LoginInputModel model, string button) method
I am in the process of implementing OAuth 2 on a web API with Microsoft.Owin.Security.Oauth.
I would like to keep the bearer token small and keep private data out of it. To do this, I'd like to store a session ID in it and then fill out the ClaimsIdentity programmatically once the session ID has been received and processed. This would also give me greater flexibility related to how logging out, role changes, and other things can be handled.
This should be a matter of intercepting the right event and adding a delegate. However, I can't find an event that gets fired on my authorization provider, a subclass of "OAuthAuthorizationServerProvider". I thought that "AuthorizeEndpoint" would do it, but it does NOT get fired for API methods decorated with the [Authorize] attribute, even though these methods clearly get checked for a valid bearer token. When I overrode "MatchEndpoint", all I found is that a call to a method that was decorated with [Authorize] showed up with "IsAuthorizeEndpoint" and "IsTokenEndpoint" both set to false. The latter makes sense to me, the former does not.
I am very confused. Can somebody who knows this library tell me what's going on and what I need to do to accomplish this seemingly simple idea?
I think you may be conflating resources marked with the AuthorizeAttribute with the OWIN Authorize endpoint. The AuthorizeEndpoint and TokenEndpoint are setup in the OWIN configuration as receivers for their respective authentication types. The Authorize Endpoint is used for web-base, user-agent authentication and is where you would expect a browser to be redirected should they be unauthorized to access a resource. The token endpoint is used instead for username-password token authentication and refreshing, and is the one you want. Assuming you are assigning both of these within your OWIN startup configuration, the event you may be looking to overload for OnValidateTokenRequest to ensure that your customizations to the token do not cause it to be invalid once the client tries to utilize it again. You would want to do your actual modifications to the token at the OnTokenEndpoint event.
The MSDN is pretty clear about MVC Routing and Security:
The only supported way to secure an MVC application is to apply the AuthorizeAttribute attribute to each controller and use the AllowAnonymousAttribute attribute on the login and register actions.
However, I am considering the following approach:
First, I have implemented a custom Controller Factory that performs security checks based on information coming from our custom STS.
Among other information, the token issued by the STS contains claims describing all the MVC routes the user is allowed to access.
Then I check the user claims within the CreateController method:
public class SecuredControllerFactory : IControllerFactory
{
public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
{
...
bool isAuthorized = principal.HasRequiredRight(verb, ressource);
...
}
}
This way we can configure and update security rules in a centralized manner, without redeploying our applications. Moreover, it fits the "convention over configuration" idea.
Is there something wrong with this approach? I don't see why it is considered a bad practice? Can someone exhibit a concrete security issue with this?
I guess it is bad practise because it breaks the Single Responsibility principle within the controller factory. The single responsibility of the controller factory should be to select and instantiate controllers.
I would question your reason for going with the controller factory approach:
This way we can configure and update security rules in a centralized
manner, without redeploying our applications.
This is a valid statement if you use the standard AuthorizeAttribute that specifies the allowed users/roles in code.
However, the recommended approach would be to derive from AuthorizeAttribute and implement your security rule logic in the derived class by overriding the protected AuthorizeCore() method. For example, it could look up permissions in a database so you could change them dynamically at runtime.
This also allows you to implement custom logic that gets called when the authorization check fails (HandleUnauthorizedrequest() method), which is presumably what you have to do in your custom controller factory when the authorization logic fails (e.g. redirect to a sign-on or error page?)
That way, you get the ability to change your security rules and manage them centrally without redeploying the whole application and you don't break the single responsibility of the ControllerFactory
ThinkTexture provide a good implementation in their identity model framework, as described here
http://leastprivilege.com/2012/10/26/using-claims-based-authorization-in-mvc-and-web-api/
This allows you to specify a Resource/Action and to encapsulate the authorization logic in a custom ClaimsAuthorizationManager in the usual WIF way. If you don't specify the resource and action explicitly in the attribute, the framework gets the values from the using the current HttpActionContext, which is nice.