Can Policy Based Authorization be more dynamic? - asp.net-core

Net Core policy authorization, however it is looking very static to me. Because in the Enterprise Application, there is an often need for new roles which will need new policies (as far as i understand) or if you want to implement new type of policy specific for certain client. For example if we are building an CMS which will be driven by those policies, we will want, each client to be able to define hes own. So can this new policy base mechanism be more dynamic or, it's idea is entire different?
thanks :))

I always recommend that people take a look # the least privilege repo as it has some great examples of all the various approaches one can take with the new ASP.NET Core Authentication and Authorization paradigms.
Can this new policy base mechanism be more dynamic?
Yes, in fact, it is more dynamic than the previous role-based concepts. It allows you to define policies that can be data-driven. Here is another great resource for details pertaining to this. You can specify that an API entry point for example is protected by a policy (for example), and that policy can have a handler and that handler can do anything it needs to, i.e.; examine the current User in context, compare claims to values in the database, compare roles, anything really. Consider the following:
Define an entry point with the Policy
[Authorize(Policy = "DataDrivenExample")]
public IActionResult GetFooBar()
{
// Omitted for brevity...
}
Add the authorization with the options that add the policy.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddAuthorization(options =>
{
options.AddPolicy("DataDrivenExample",
policy =>
policy.Requirements.Add(new DataDrivenRequirement()));
});
services.AddSingleton<IAuthorizationHandler, MinimumAgeHandler>();
}
Then define the handler.
public class MinimumAgeHandler : AuthorizationHandler<DataDrivenRequirement>
{
protected override void Handle(
AuthorizationContext context,
DataDrivenRequirement requirement)
{
// Do anything here, interact with DB, User, claims, Roles, etc.
// As long as you set either:
// context.Succeed(requirement);
// context.Fail();
}
}
Is the idea entirely different?
It should feel very similar to the previous concepts that you're accustomed to with auth8 and authz.

The accepted answer is still quite limiting. It doesn't allow for dynamic values at the Controller and Action level. The only place a custom value could be added is in the requirement when the policy is added. Sometimes you need more fine grain control over the authorization process. A very common scenario is permission based security. Each controller and action should be able to specify the permissions required to access them. See my answer here for a more powerful solution that lets you use custom attributes to decorate your controllers and actions with any information you need while doing authorization.

Related

ASP.NET Core Custom Authorization

I need to implement role based authorization on a .NET 5 API but the thing is that we don't want to decorate all the controllers with attributes and a list of roles, because all that configuration will come from either a config file (JSON) or an external service (TBD), in a way that roles will be mapped to controllers and actions and we would want to have something that centralizes all this logic, in a similar way we did before with Authentication Filters and Attributes.
I've been reading that now the idea from MS is that everything is handled with policies and requirements, but I don't know how to fit all that into our desired schema. Most of all because I don't see (or can't see) how can I access the Controller and Action's descriptors to know where I'm standing when I perform the authorization process.
Is there any way to achieve this on this new model?
EDIT: I found a way to get controller and action descriptors in order to do part of what I intended. Based on some other questions and articles I read and some tinkering on my own, I got the following:
public class AuthorizationFilter : IAsyncAuthorizationFilter
{
public Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
var descriptor = (ControllerActionDescriptor)context.ActionDescriptor; //<<-- this is the key casting :)
var ctrlName = descriptor.ControllerName;
var actionName = descriptor.ActionName;
var userPrincipal = context.HttpContext.User;
//DO STUFF AND DECIDE RESULT TYPE BASED ON USER CLAIMS AND CURRENT CONTROLLER AND ACTION
context.Result = new ForbidResult();
context.Result = new UnauthorizedResult();
return Task.CompletedTask;
}
}
Then I could add this filter the following way:
services.AddControllers(x => x.Filters.Add<AuthorizationFilter>());
This way I could achieve something similar as before with ASP.NET MVC 4/5, but from what I can read, the .NET Core team tried to go away from this path by implementing the IAuthorizationRequirement and AuthorizationHandler<T> mechanism to replace all that, so my doubt remains: is this the correct way to do it in the new .NET Core 3.x / .NET 5 architecture? Or is there some other way I'm overlooking on how to get and process the controller/action being executed and pass it along to an AuthorizationHandler?
What you are looking for is called externalized authorization also referred to as attribute-based access control. In this model:
authorization logic is decoupled from the application
authorization logic is expressed as policies that build on top of attributes
attributes are key-value pairs that describe the subject, the action, the resource, and the context of what's going on (A user wants to execute an action on an object at a given time and place)
authorization is decided based on those policies in a logical central point (logical because you could very well have multiple instances of that central point colocated with your app for performance reasons). That logical central point in abac is known as the Policy Decision Point (PDP)
authorization is enforced based on the response back from the PDP in the place where you want to enforce it. This could be at a method level or at an API level or even a UI level: you choose. The component in charge of enforcing the decision is called a Policy Enforcement Point (PEP).
There's one main standard out there called xacml and its developer-friendly notation called alfa that will let you implement attribute-based access control. It's worth noting this model and approach is applicable to any app (not .NET-specific at all).

How to properly do resource-based authorization in ASP.NET Core 2.2?

I have an ASP.NET Core 2.2 application where I am displaying some documents. Most documents are public, so anonymous access is fine. However, some documents are private (i.e. they require authentication/authorization), and in the future some documents might also require a valid subscription. All documents are retrieved using the same actions, so we only know the required permissions after the documents have been loaded. We also load some resources as static files (IApplicationBuilder.UseStaticFiles), but I guess that shouldn't really be an issue as StaticFileOptions.OnPrepareResponse can be used for custom authorization code.
The logic for who gets access to private documents is currently really simple. And at the moment, we only display documents, we don't allow any other kind of operation on them (editing, deletion etc.). To me, this sounds like a pretty standard case of resource-based authorization.
Anyway, I have found this article and from what I've understood, I need to define a policy (identified by a magic string - what's up with that?!) as well as a requirement and an AuthorizationHandler<MyRequirement, MyResource> which will perform the actual authorization logic. Then, inside my controller action, I will need to call IAuthorizationService.AuthorizeAsync and pass in the user, the resource and the policy name (the magic string) and, based on the result from that method, allow or deny access. That seems more than convoluted for what I'm trying to accomplish. It would probably be easier if I simply defined my own kind of "authorization service" and simply dropped the whole policy and requirement stuff. I also think it's less than ideal that I would have to replicate the if-else logic in all affected controller actions.
Surely I'm not the only one with this issue. Is there something I've missed?
If there are indeed good reasons for using policies and requirements, how would you name them in a case like this? I'm really feeling a little lost.
Maybe it would make sense to use the type of document (public, private, subscribers-only) as the policy name?
In the end, we didn't want to deal with this stuff and just wrote our own AuthorizationService, which is injected into the controller like any other service.
It loads the required permissions for all documents the first time it is used and caches them.
Our controller methods then look something like this:
[HttpGet("[action]")]
public async Task<Document> GetDocument(string documentId)
{
if (_authorizationService.MayAccess(User, documentId))
{
return _documentRepository.GetDocument(documentId);
}
else
{
Response.StatusCode = StatusCodes.Status403Forbidden;
return null;
}
}
I recommend the last approach explained in this article - https://www.red-gate.com/simple-talk/dotnet/c-programming/policy-based-authorization-in-asp-net-core-a-deep-dive/
Allows you to keep you controller clean, by just applying annotation with the name of the policy. In the handler you must implement the logic checking if person can access the resource - it can be based for example on checking a property ownerId in a resource(for example in database table column) or a member of a certain group in AD, or anything else.
EDIT:
Using Requirements and RequirementsHandlers - I have done something similiar.
I don't know how should your logic exactly work, so I am just going to assume some.
lets say you have a get endpoint: documents/documentId
You want to apply logic which will make this document accessible only to the document owner. Obviously, you need somewhere to store who is the owner of the document, so lets keep that in property of a document entity.
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, IsDocumentOwner requirement, DocumentRepository documentRepository)
{
if (context.Resource is AuthorizationFilterContext ctx)
{
var documentId = ctx.RouteData.Values["documentId"]?.ToString();
//here load document from repo and check if the property ownerId is equal to current user id
var userId = context.User.Claims.FirstOrDefault(x => x.ToString().Contains(oid))?.Value;
//if yes, make the request pass to the body of a controller with the attribute
context.Succeed(requirement);
}
}
implement IsDocumentOwner:
public class IsDocumentOwner : IAuthorizationRequirement
{
}
in your Startup.cs add:
services.AddAuthorization(options =>
{
options.AddPolicy(
nameof(IsDocumentOwner),
policyBuilder => policyBuilder.AddRequirements(
new IsDocumentOwner()));
});
then, last step, apply attribute on your controller method
[Authorize(Policy = "IsDocumentOwner")]
[HttpGet("{documentId}")]
public YourDocumentObjectResultClass GetDocument([FromRoute]string documentId)
{
//stuff you do when current user is owner of the document, probably just display the doc
}
To your IsDocumentOwner handler you can inject any service by constructor(visualised by repository above), for example, to check if the user is a member of a group on azure ad

.Net core Authorize attribute in inherited controller

I am having some trouble with Authorization policies. I have a baseWebApiController with an action
[HttpDelete("{id}"), Authorize(Policy = "Administrator")]
public virtual async Task<IActionResult> Delete(int id) {}
But in a certain controller which inherits from the above I want to give access to users also, with a policy like:
[HttpDelete("{id}"), Authorize(Policy = "All")]
public override Task<IActionResult> Delete(int id){}
It seems regular users cannot access this action. Do I have to search further for errors in my policy configuration, or since the controller is inherited,m it's attributes are neglected?
Thanks
The AuthorizeAttribute is an attribute that is inherited and that allows itself to be applied multiple times.
That means when inheriting your method which already has an AuthorizeAttribute, that will be carried over. So the final function definition in your subclass would look like this:
[Authorize(Policy = "Administrator")]
[Authorize(Policy = "All")]
public override Task<IActionResult> Delete(int id)
So the route now has two policies in place. This is kind of a problem because policies are designed to be cumulative. So all policies have to pass in order for the authentication to succeed.
Of course, this will not work for you because you actually wanted to “wash out” the original policy from the base class. This is not possible though, so you would have to remove the policy from the base class and maybe introduce a second administrator-only class for those policies.
The general problem here is that your policy design seems to be based on roles. You are using policies, but effectively, you are checking on roles there. Instead, you should consider working with requirements: For example, to delete something, a user would need to fulfill the “DeletionAllowed” requirement. This allows for a much more fine-grained policy system. And the big benefit? Requirement handlers are disjunctive: So one handler that is able to fulfill the requirement is enough to pass it.

No storage mechanism for grants specified

I am new to IdentityServer and am having a little trouble setting this up.
For reasons I won't go into here I can't use ASP.NET Identity or EntityFramework. I have a custom database for users that I need to authenticate against so I took the samples and tried to switch out the InMemoryUsers for a custom persistence store.
Here is my ConfigureServices method:
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentityServer(options =>
{
options.AuthenticationOptions = new IdentityServer4.Configuration.AuthenticationOptions
{
};
})
.AddInMemoryClients(Clients.Get())
.AddInMemoryScopes(Scopes.Get())
.SetTemporarySigningCredential();
services.AddMvc();
services.AddTransient<ISignInService, SignInService>();
services.AddTransient<IUserRepository, UserRepository>();
services.AddTransient<IUserService, UserService>();
services.AddTransient<IResourceOwnerPasswordValidator, ResourceOwnerPasswordValidator>();
services.AddTransient<IProfileService, ProfileService>();
}
I know this method is imperfect as I am still testing some things, but when I run the application I get this error:
System.InvalidOperationException
No storage mechanism for grants specified. Use the 'AddInMemoryStores' extension method to register a development version.
Obviously I don't want to use in memory stores for a production implementation, but I am not sure what I need to do to fix this.
AddInMemoryStores does not have the best name. It actually adds the store for all the transient data that relates to issued materials/tokens.
We use it in production sometimes because a lot of the time we don't really need to persist this data to disk, and we don't use long lived tokens.
Take a look at what the extension method does here and look at what the IPersistedGrantStore contract looks like to get a better idea.

IAuthenticationFilter equivalent in MVC6

I'm moving a Web Api 2 project to MVC 6, since Microsoft is merging the two APIs in ASP.NET 5. In my WebApi project I had a custom Attribute Filter class that would authenticate, authorize and prevent transaction replays using a combination of public key, private key and HMAC authentication (basically, doing this with some tweaks to fit into my project).
Now in MVC6, as far as I understand I must stop using anything in the Microsoft.Web.Http namespace and instead use Microsoft.AspNet.Mvc. So I have done that, but the Microsoft.AspNet.Mvc.Filters doesn't seem to have any equivalent of Web Api 2's IAuthenticationFilter.
This is a problem for me because my customer AuthenticationFilter implemented all of IAuthenticationFilter, with all the logic in there. More importantly, it was using the Context to temporarily store the public key of the account, so my controller could access it to load up the account in turn.
So my question is, what is the proper way to filter requests in MVC6, using an Authentication Filter-like class to intercept the requests and return the appropriate status codes? I can't find any article that goes specifically in these details (they all tend to cover MVC5).
I know it's an older question, but hopefully someone (maybe even yourself) might find value in the answer.
MVC6 does in fact have an alternative. You have an
public abstract class AuthorizationFilterAttribute :
Attribute, IAsyncAuthorizationFilter, IAuthorizationFilter, IOrderedFilter
which basically tells you, that you can create your custom class, derive it from this (namespace of all of these interfaces, btw, is Microsoft.AspNet.Mvc.Filters and that should be it. You can either decorate the action with it, or you can do this in Startup.cs, to apply to all actions:
public void ConfigureServices(IServiceCollection services)
{
// Add MVC services to the services container.
services.AddMvc(options =>
{
// add an instance of the filter, like we used to do it
options.Filters.Add(new MySpecialFilter());
});
services.AddTransient<LogFilter>();
}
If you want to use a bit more logic in the filter (e.g. my LogFilter above) which is instantiated through DI, you need to use either Service Filters or Type Filters.
You can now decorate the actions with [ServiceFilter(typeof(LogFilter))] or use o.Filters.Add(new ServiceFilterAttribute(typeof(LogFilter))); in the Startup.cs file. But keep in mind, to do this you need to register the type with the DI container, like I did above with the .AddTransient<>() call.
IAuthenticationFilter is no more and IAuthorizationFilter simply does not replace it in MVC 6
Reason: authentication is NOT EQUAL to authorization.
Therefore IMO the authentication filter should stay available!