micronaut-projects / micronaut-security

The official Micronaut security solution
Apache License 2.0
170 stars 127 forks source link

Securing routes by JWT Claims #256

Open ashwini-desai opened 4 years ago

ashwini-desai commented 4 years ago

It is a common practice in claim based authorization approach, to allow or disallow a user from accessing a resource, based on claims available in JWT.

I see we have @RolesAllowed annotation that lets us do the same for role based authorization. Similar to Issue#254, a SecurityRule could be provided for checking claims. This will help the requests to be rejected even before entering controller logic. E.g ASP.NET Core provides @Authorize(...)

The logic could be made generic as well since roles, scopes everything are a claim against which we want to implement all these checks.

Is something of this sort already in pipeline?

graemerocher commented 4 years ago

Not that I am aware of, maybe @jameskleeh can provide a better answer

PRs are of course welcome

jameskleeh commented 4 years ago

@ashwini-desai Can you provide an example of what claim you want to check? How would the framework know:

  1. What claim to check
  2. What value to compare it against
  3. How to compare the values

Is this specific to scope? If so, this would duplicate https://github.com/micronaut-projects/micronaut-security/issues/254

traycho commented 4 years ago

I think this topic becomes more popular, i was working on something similar.

@jameskleeh Is it possible to incorporate something of this kind https://github.com/traycho/micronaut-security-attributes under micronaut-security-jwt

I am ready to assist standardising it , any feedback is welcome.

ashwini-desai commented 4 years ago

@jameskleeh Missed this thread earlier.

Example could be very similar to how @RolesAllowed is implemented. To answer your questions:

  1. What claim to check - It could support a key value check like @ClaimAllowed("sub", "xyz") or like how we can configure a key for roles, we could let users defined custom key which could be an array etc that holds custom claims in a token and @ClaimsAllowed("value1", "value2") etc

  2. What value to compare it against - Value can be provided in the annotation as mentioned above

  3. How to compare the values - For key and value, it could be done easily, for @ClaimsAllowed where only values are passed, it could be done using claims key configured in security configuration.

dstepanov commented 4 years ago

You can override RolesFinder and provide extra roles from claims.

ashwini-desai commented 4 years ago

@dstepanov RolesFinder by the name is meant for checking Roles only. We could provide an implementation, but doesn't sound correct. Also, in general there could be a lot of rules between different claims in the token which could be provided as rules, which will be helpful. So just overriding RolesFinder might not help in the longer run. Check this project as an example.

sdelamo commented 4 years ago

Yes, I think this is a new feature. I think we could support a @ScopesAllowed annotation or a similar name.

ashwini-desai commented 4 years ago

@sdelamo Yes, we could provide generic annotation which can take one or many security attributes from the token and expected values, give enhancement options for AND/OR between them. This will make it work for all attributes, we won't have to make specific annotations like @ScopesAllowed then.

adrnola commented 3 years ago

@sdelamo / @jameskleeh - Can you provide an update on this issue 256 which relates to 254. Do you foresee this being implemented anytime soon ? This would be especially useful for the OAUTH 2.0 Credentials Flow (Machine-To-Machine) which is becoming more prevalent in usage

jameskleeh commented 3 years ago

@adrnola I'm not convinced its feasible to implement claims validation at the framework level because there is no sensible default on how to verify the value of the claim is correct. We could implement a simple @ClaimEquals(claim, value) sort of annotation but I'm not sure how valuable that is. We could also implement an annotation to assert one of the provided scopes is set in the claims, however each of these tasks is not very complex and can be achieved today in any given application. The API to implement this functionality is public and open to anyone to use. I can't give a timeline when we might implement something related to this feature, however if you have a proposal we are willing to evaluate it.

adrnola commented 3 years ago

@jameskleeh - Thanks. I did some more investigating into this.

I now have the following configuration:

[1] CustomJwtClaimsValidator implements GenericJwtClaimsValidator - which I use for Authentication of JWT (isIssuerValid && isAudienceValid && isGrantTypeValid && isAuthorizedPartyValid && isNotExpired) by validating using application.xml entries below

[2] I created a Custom SecurityRule and created a corresponding Class/Method Annotation - which I use for Authorization (which checks value of the scope).

[3] applciation.xml security: enabled: true token: jwt: signatures: jwks: auth0: url: https://myApp-test.auth0.com/.well-known/jwks.json

These entries are not Micronaut Framework Specific - They are Project Specific.

          # They are placed here as they are JWT/Auth0 specific.
          issuer: https://myApp-test.eu.auth0.com/
          audience: https://myApp-test.com
          grant-type: client-credentials

which worked a treat and is very flexible in my Controller: @JwtAuthorization(scope = "foo:bar") @Post(value = "{something}") public HttpResponse doSomething()

I am just wondering what is best practice here, move Authentication from CustomJwtClaimsValidator to SecurityRule and use SecurityRule to do both Authentication & Authorization ?

I think where mine and other people (on this thread) confusion arouse is that the Micronaut Doc's does not have a concrete example in the use of SecurityRule & Annotation to validate the JWT.

Thanks.

frehov commented 3 years ago

I'd like to chime in here with the same answer I've given on #254.

If you're not including roles in the claims, then you can use micronaut.security.token.roles-name=scope to remap the ttribute used by the default RolesFinder and use the @RolesAllowed annotation to achieve securing routes with scopes from JWT. This would only work as long as you're not dependenent on mapping roles from the default role-attribute as well.

This answer may be skirting the core issue about providing a mechanism to check other claims other than scope, but for those that only need to remap where roles are read from to secure their application, it should be fine.

This property has afaik been available since micronaut 1.0.0