Let's consider a fairly simple hypothetical application where users can read or write posts.
Some users can read and write articles while some others can only read them. With Spring Security (3.2.1) I modeled this by having 2 roles:
ROLE_WRITE: this role grants users access to writing posts.
ROLE_READ: this role grants users access to reading posts.
Implementing this with Spring security is fairly straightforward...
Now I want to also allow third-party apps to read and write posts on behalf of users by implementing an OAuth2 provider using Spring Security OAuth (version 2.0.0.M3 ATM).
During the authorization step, the app asks the user whether they are willing to grant the right to read and/or write posts on their behalf. The user here is granting scopes here (not roles).
Then when the OAuth2 consumer calls my REST API, Spring Sec OAuth authorizes the token granted and creates an authentication containing the user with all their roles and only the scopes granted.
The problem (and the question) is that I now have to write different security logic depending on whether the API is called by a user normally authenticated (just check the roles) or whether it's called through OAuth2 (check roles + scopes).
Is it possible to "merge" the concepts of roles and scopes in Spring Security OAuth2 so that during the authorization step, the user grants the app a subset of the roles they have (and have the OAuth2 authentication only report these in the granted authorities)? That way when the 3rd party app makes an API call, the roles on the authentication are the ones granted? That way I don't have to write any OAuth2 specific security logic.
Scopes (and roles) are arbitrary strings, so there is no problem if you want to make then the same. To make the access rule declarations identical you could write an ExpressionHandler that tested authorities or scopes with the same values depending on the type of Authentication it found.
A different approach suggests itself after you read the comments: add a custom TokenStore or ResourceServerTokenServices. These are easily accessible extension points and would permit modifying the OAuth2Authentication so that its granted authorities were the same as the scopes.
My preference, however, is to control the allowed scopes using a OAuth2RequestFactory, limiting them at the point of the token grant to values that are consistent with the user's authorities.
You can configure your own AccessTokenConverter (mainly for JWT) and extract the claims you want from the JWT access token and generate an Authority object. Just define a Bean factory that return an AccessTokenConverter
Related
So we are building an application which has to support two ways of creating a new account.
user creates an account with a email and password combination
user adds an Authorization header with a JWT token from a trusted third party. This JWT is verified and contains the necessary information such as email to create a user in our system.
Creating a user this way works fine. However, I am not sure how to deal with the subsequent authentication. The current system uses session-based authentication.
Question: A user that created an account with the JWT should also be able to login without a password. I can think of two way to achieve this:
Validate the JWT and manually start a session. But how can I start a session manually without a password?
Add a filter to the Spring Security Chain that checks whether a JWT is present. If so it adds the user the the security context. If no JWT is present it requires the user provide a valid email, password combination. Any resources on how two do this conditional chaining?
Any hint for an advantage or disadvantage for the two methods is appreciated.
Currently our spring boot app uses okta for login. There is a need to implement RBAC for the application so I was trying to see if I can leverage okta itself for mapping users to specific roles.
I would like to implement the standard RBAC model in which I would map multiple permissions under a role and the roles are associated to users. Basically it involves 3 levels permissions > roles > users.
But in okta I don't see the standard way for mapping roles and permissions. RBAC is achieved by creating groups and associating groups to the users, which is two levels. And groups needs to be added as a custom claim.
How do I achieve the standard RBAC mapping(permissions > roles > users) in okta or it's something that needs to handled outside the IDP provider.
Thanks in advance.
Possible Solution:
You can make the scopes (scp in access token) be your permissions. Below are the steps:
In your Authorization Server, create your custom scopes(permissions) and set them as default scopes (this is necessary).
For example create 2 default scopes:
books.read (default=true)
books.write (default=true)
Go to access policies in your Authorization Server create one if none is defined.
Create access policy rules in the access policies page, the rules will be your mapping between groups and scopes.
Test that in Token Preview tab, the trick here is to leave scopes field empty so that the Authorization server can return the default scopes that are set for the user, as explained by Okta:
A default scope will be returned in an access token when the client omits the scope parameter in a token request, provided this scope is allowed as part of the access policy rule.
Now in your application when requesting an authorization code make sure that scope query param is empty.
Depending on the library you are using you may face some issues if by default they are expecting an id_token to be always returned but you will probably be able to customize it. For example: https://github.com/okta/okta-auth-js/issues/827
Solution Limitations:
As mentioned in steps 4 and 5 we are omitting the scope query parameter, this mean that only our custom scopes assigned for the user or his groups will be returned, since the base scopes that are predefined by Okta such as profile, openid, email ... will not be returned. Which also means that we are skipping OIDC which needs the openid scope, so id_token will not be returned and only an access_token will. So this solution assumes that you don't need any of the base scopes predefined by Okta.
In case you need any of the base scopes
As described in the limitations, the solution assumes that you don't need any of the base scopes predefined by Okta. But in case you do then below is a solution that works in that case but not that nice.
When requesting an authorization code in the oauth flow, you need to send the request twice
first one: omit scope query param, so the default scopes are returned.
second one: append the returned scopes returned from the first request to the list of base scopes you wanted such as openid, profile, 'email`. So you would send something like (encoded already)
?scope=books.read%20books.write%20openid%20profile%20email
Disclaimer:
The above solution may not be recommended, but it works. If anyone can find any security issues with the above solution please leave it in the comments.
When you get into the details of roles and permissions, the data tends to be domain specific and to change often. I would advise against trying to manage it in the Authorization Server.
One design pattern that will give you full control over claims is to form a custom AuthenticationPrincipal that includes roles or permissions from your application database(s).
If interested in this pattern, see these resources of mine:
Custom Claims Blog Post
Java Custom Claims Code
How to run Java Code Sample
Our system is moving from a monolithic to a microservice architecture.
The microservice architecture comes with technical challenges that we need to address and one of them is AuthN/AuthZ.
Our approach is to have an authentication service that would authenticate users and generate access/refresh tokens (JWTs).
Access tokens would then be passed in request header through the chain of microservices such that each microservice just have to validate the token to determine the user has been successfully authenticated.
For the AuthZ part, permission enforcement is done in the microservice itself. My questions are related to AuthZ.
To illustrate the talk, let’s take a specific example of a receptionist who wants to register a new member to his fidelity program, for instance from a Web application.
To support this use case, let’s assume the system has 2 microservices, the ReceptionService and the MemberService.
The ReceptionService offers one REST API to initiate the member registration flow. It requires user permission “registration” to allow execution.
The MemberService offers one REST API to create a new member resource which is protected by CRUD permissions.
A request flow would be:
The web application, on which the user has previously logged in, sends a member registration request to the ReceptionService API including the user access token in the header.
The ReceptionService validates the user token, ensures user is granted with permission “registration”, does whatever business logic it needs to do, and finally sends a member creation request to the MemberService API including the user access token in the header.
The MemberService validates the user token, ensures user is granted with permission “member.create”, and finally creates the member.
To design a solution for such case, my team worked on the following assumptions/prerequisites:
A microservice must always enforce permission (at least for significant API operation such as creating a member). Thus the CRUD permissions on the MemberService in the example above even if Products Managers might only require the top-level “registration” permission.
A user who is able to start a use case because it has the “top-level”
permission must be able to complete it. Meaning It shall not get
errors because he is lacking another permission from somewhere in the
underlying services’ call chain.
Admin users shall not have to understand the chain of permissions
that is required to perform a use case. In our example, Admins should
be able to provide users only with the “registration” permission.
To be able to complete the above example, there are 2 different permissions to be assigned to the user, which breaks some of our assumptions/prerequisites. To overcome that, one of my colleague proposed to consider declaring microservices as identities/users in our AuthN system so that they could be assigned with the appropriate permissions. The user token initially provided would then be replaced by participating services token among the call chain.
To come back to the example, the new request flow would be:
The web application, on which the user has previously logged in,
sends a member registration request to the ReceptionService API
including the user access token in the header.
The ReceptionService validates the user token, ensures user is
granted with permission “registration”, does whatever business logic
it needs to do, and finally sends a member creation request to the
MemberService API including its own service token in the header (and
so replacing the original user token).
The MemberService validates the service token, ensures service is
granted with permission “member.create”, and finally creates the
member.
With this solution, service’s identities in the AuthN system would be flagged in a way that they are filtered from an Admin user managing permission assignments. Permission assignments to services identities would be pre-defined with no possibility for a user to configure it. While it fulfills our assumptions/pre-requisites, I have few concerns about this approach:
When dealing with the “who did what” (audit), user identity and
service identity provided in the tokens would be listed
indifferently. In our example, the RegistrationService would audit
the actual user who initiated the operation but the MemberService
would audit that the operation was performed by the
“RegistrationService”. In reporting scenarios, it means I would need
to reconciliate audit from both systems to determine “who actually
did create the member” using somehow a correlation ID.
While I understand the need to create an identity for a system
component in scenarios which do not involve an actual user (automated
batch/third party access ..), I am not comfortable with replacing the
user token with a service token in scenarios where a user actually
initiated the use case. Is that a standard design pattern?
Could it be that some of our assumptions/prerequisites just wrong?
For instance, is it really a security hole that some microservices do
not enforce permission even if they are only accessed by others
controlled microservices in a safe environment? Assuming the answer
to the latter is “no, it would not be a security hole”, then what if
tomorrow, I need to make the MemberService API also accessible
outside of the safe environment (for instance, because I make it
available to a third party). I would most likely need to add a
permission on it, which would break my registration flow.
Is it wrong to say we do want Admin users to know which set of
permissions are required for a use case and that we should rather
build the system so it gracefully handles failures due to lack of one
permission in the call chain (maybe using Sagas and compensation
routines)?
Any comment or links to resources would be greatly appreciated.
Thanks!
Each service should own it's own permission-schema, but I would recommend you using Service Mesh to not Authenticate user throughout each hop/Microservice.
I am applying spring security to a web application where i need to do the following:
Limit access to certain pages for certain roles/authorities
Limit access to certain data based on user access and user role (for
example admin can see all data, a user can see only data on which the admin granted access for the user)
Allow actions on data based on the access right the user has (read,
manage, etc)
So, i was thinking:
Limit access to certain pages for certain roles/authorities -> use
hasRole
Limit access to certain data -> filter directly in the queries
getting the principal from the security context
Allow actions on data based on the access right the user has -> use
my custom PermissionEvluator's hasPermission method
Now this is a setup i came up with, but would like to know if this makes sens and if it is according to a good use of the spring security framework or am i simply twisting it too much.
Spring security provides all these features and makes implementing these features simple. Yes your approach is right. you can add below cases.
security none: allow unauthenticated users access to certain
pages.(login, public pages) authenticated: allow access to
authenticated users.. (general access to all registered users)
restrict based on role: readonly, editor/manager, based on
permissionEvaluator on the data user has access to
You can also use spring security to protect your web application against malicious users with features like
- CSRF protection (enabled by default)
- XSS protection
for further detail read: spring security manual
I'm fairly new to Oauth2 and it seems I'm stuck.
To protect our API, we use OAuth2. We have a lot of calls that contain information based on an account, se we use the password grant in OAuth.
But, I also have to protect my registration call, so only registered applications with valid client_id and client_secret can use that call. So, after reading a while, it seemed that I needed to use the client_credentials grant for those calls.
But now, I have absolutely no idea how I can define witch call should be using password of client_credentials.
Am I thinking wrong and is it impossible to use a specific grant for a specific call, or how can I define when to use what grant?
FYI: I'm using Laravel5.1 and Luca Degasperi's Laravel OAuth2 server
Thanks!
Usually you won't limit calls or routes to specific grant types and for several reasons it's nearly impossible to limit the client-application access via oauth grants.
So as a rule of thumb you should only expose the endpoints the user is allowed to access doesen't matter which client is used.
Further more I would prefer the client credentials or owner credentials grant, it's better in facts of usability and security (Change Password, Remove Access for specific apps, ...) more about the different grants.