12

The distinction between roles and claims is that roles describe a set of users and claims describe a property of a user. So there can be a role "Administrator", but there can also be a claim "HasElevatedPrivilegeBadge". Both can allow the same action. Now which one should I pick if I want to allow only certain people to do certain things, for example:

CanAddItem, CanUpdateItem, CanDeleteItem,
CanAddProduct, CanUpdateProduct, CanDeleteProduct

I could create role "Administrator" and add to it claims "CanAddItem", "CanUpdateItem", etc., but "CanAddItem" doesn't describe a property of a user. It says what the user can do, which is not what a claim should do, should it?

Another approach is to create policies, such as:

policy.AddPolicy("CanAddItem", policy => {
    policy.RequireAuthenticatedUser()
          .RequireRole("Administrator");
});

But for more than 20 policies, it will take a good chunk of my Startup class. Is there any other way of doing this, or is one of these the preferred one?

I'd like to point out that I'm specifically looking for a solution for .Net Core Identity. I'm asking for a solution on how to fit my requirement into Identity tables provided by the framework.

4 Answers 4

6

Essentially you are describing a mapping of Role to Permission.

I think this is pretty much covered by the standard [Authorize(Role=xxx)] on your controller actions, where the implied permission is CanExecuteThisAction. No need for extra policies as they would simply act as a mapping, potentially confusing the issue and as you say, adding a lot of boilerplate code.

The policies seem to be aimed at more complicated permissions, where you need to execute some logic against the claims or other properties of the user, the example being the AtLeast21 policy where the users claim is a date of birth.

They would I guess replace custom AuthorizeAttribute classes.

I would not use them when the default Authorize attribute can handle it on its own, such as with role checking.

2

I generally opt towards policies since they allow for granular and expressive control over authorization. To address the concern over them taking up space in the Startup class, you could break the policies out into a static class.

internal static class Policies
{
  public static void CanAddItem(AuthorizationPolicyBuilder policy)
  {
    policy.RequireAuthenticatedUser()
      .RequireRole("Administrator");
  }
}

And then in Startup.cs registering each policy is a one-liner

services.AddAuthorization(options =>
{
  options.AddPolicy(nameof(Policies.CanAddItem), Policies.CanAddItem);
});

If you needed even more control, you could consider adding in a custom IAuthorizationPolicyProvider which lets you programmatically resolve policies.

https://docs.microsoft.com/en-us/aspnet/core/security/authorization/iauthorizationpolicyprovider?view=aspnetcore-2.1

1
  • Thanks, I thought about putting policies in a different file. I'm just wondering if anyone else does that and if this is maintainable.
    – FCin
    Commented Sep 25, 2018 at 14:12
2

Disclaimer: I never used policies before. I think the answer to your problem also depends on the identity provider you are using. if the identity provider is not your own application but a third party identity provider OR a standardized product like identity server 4, using Roles and claims would be better, since OAUTH / openidconnect can work with roles / claims nativley.

We use a schema like your schema, but slight twists: 1. We have multiple roles, e.g. an administrator, itemManager and a user. 2. We have claims like "item.add", "item.delete", "item.create" 3. Each role can have N claims 4. Each user can have N roles This allows for a lot of composability, e.g. a user can get the claim "item.delete" due to him beeing an admin or because he is an itemManager.

It is important that the claim names need to be somewhat standardized and that their granularity is appropiate for your application - e.g if the right to create an item and to update it are logically connected, create only one claim, not two.

Furthermore, you can use roles to insert a little bit of business logic, like product.maxnumber.200 => the user can only have up to 200 products, which needs to be validated by your business logic.

Lastly, several security papaers I have read the last months (OWASP) recommended to place authorization next to your business logic due to the fact that often the question "can the user do that?" needs to be answered within the context of the business logic: "does the user have the roles product.add AND does he have less than product.maxnumber products?" -> such a context is easy to obtain in a particual request, but difficult to answer generally, like in policies.

2

I could create role "Administrator" and add to it claims "CanAddItem", "CanUpdateItem", etc., but "CanAddItem" doesn't describe a property of a user.

Depending on your point of view, your example may just be a bit too pragmatic.

From another point of view, a person who is 21 is also of legal age to drink, but they aren't Can Drink Alcohol right?

Back to your example, whats the difference between `Product Creator, Product Changer, and your examples? To me it's just the point of view, with one being more descriptive of what they are vs what they can do... even though really it's the same thing when it comes to your claim.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.