TL;DR
Objective: managing api permissions:
OIDC authorization direct grant flow
User federation and authentication source : LDAP
Permissions store : legacy database
Client management and authentication: Keycloak
Question: What are the best practices for managing user permissions on Keycloak and rest api?
Context
We are implementing a rest API with spring to be used by a mobile application and an SPA. Our users accounts, permissions, rules… and all data are stored in a custom database used by different monolithic applications. To secure our api we have decided to use Keycloak.
The keycloak server is configured with an existing LDAP for user federation and ‘Direct grand flow’ for the mobile client application. For the first use case (authentication) everything is working fine.
Now we have to manage users permissions as follow :
The client applications should know user permissions to display/hide functionalities
The api should be able to validate user permissions to use different endpoints
Users permissions are based on some rules in the database and change frequently
In my understanding keycloak can handle authorization and fine grained permissions using hardcoded or user based policies but can’t be plugged to a different authorization source natively. As a consequence, I thought of building a custom role mapper using Keycloak SPI, retrieve user permissions from a custom api that I will develop, then map them to the access token.
As a result, my access token should look like:
"resource_access": {
“My-client”: {
“permissions”: [
“Show-products”,
“Buy-something”,
“Display-prices”
]
}
},
"username": “myUser”
Then the mobile application should be able to know user permissions based on the token, and my stateless server side (API) should be able to access user permissions on every call to check them using spring annotation :
#PreAuthorize("hasRole('Show-products')")
Problem
After first experimenting my solution seem to work fine, but I still have some security concerns about this choice since it’s out of the keycloak standard and includes rest calls to a different backend inside keycloak mappers.
So I was wondering :
Is it secure to put user permissions on the access token claims?
How to secure keycloak access to an external system (rest calls) to
retrieve permissions?
Should I rely on token claims to verify user permissions on each
request in my resource server?
Is there any other clean solution / best practices to handle user
permissions from external source in keycloak ?
Complimentary Informations
I’m using :
Springboot 1.5.13.RELEASE
Keycloak-adapter-bom 3.4.3.Final
Standalone keycloak server 3.4.3.Final
regarding your questions:
- Is it secure to put user permissions on the access token claims?
Yes, capabilities can (and should be) on the access-token, and with that you can take some decisions in your business layer (based on the roles/access claims). Remember nevertheless that a token is only base 64 encoded, and could be copied by other person and looked into, so it shouldn't contain secret or particularly confidential information, usually you put there enough info regarding the user, and some of its current permissions/capabilities/claims.
How to secure keycloak access to an external system (rest calls) to retrieve permissions?
It depends if it needs to be accessed from outside your network. If not, you can leave it unprotected (and unavailbale from outside/or only available for some specific IPs). If it is going to be available from outside/or you want to protect it with keycloack anyway, you can have either a "confidential" or a "bearer only" type of client. I'd suggest you to look into CORS and token sharing, so that you can reuse your already created "access-token" for your other endpoints without the need to authenticate again.
Should I rely on token claims to verify user permissions on each request in my resource server?
Not exactly sure what you mean. In keycloak the resource server isn't doing extra resource authorization like in a typical oAuth2 dance (unless your policy enforcer is activated but I believe you didn't go with this approach, but rather a mapper SPI #auth server for getting your roles right?)
In oAuth2 the "resource server" has 2 responsibilities: 1-providing the resource and 2-doing an extra authorization step. In the keycloak world those 2 steps are done by different actors. Step 1 is done by your application, and step2 is only done when policy enforcing is activated by keycloak also (that means Keycloak is the auth server and also part of the "resource server" from the oAuth2 perspective)
Now back to your question, if by resource server you just meant your application providing the content, then yes you can use the claims there, remember that the claims (and the whole access-token) was generated and digitaly-signed by the auth server, so you can use those claims in your app with no problem (and wouldn't know how to do it otherwise either).
Is there any other clean solution / best practices to handle user permissions from external source in keycloak ?
Hard to say, as you probably noticed; documentation in the web for your specific usecase is very limited; so not a lot of work of best practices exist there, you only real alternative would have been using policies with a custom Policy SPI, and that would have brought in other challenges. I'd say your solution is fine.
Best regards.
Related
I'm attempting to setup a resource server that hosts resources that require different levels of security.
Through a web application I want to authenticate the users, by specifying the lowest Authentication Context Reference (e.g. basic email/password authentication). This provides an acr value for the session to the resource server. User can then access basic functions of the resource server.
If user wants to access resources of higher security, the resource server should redirect user to authorization server. This redirect should specify a higher ACR.
Within the authorization server, this new value ACR would trigger another authnetication flow including MFA.
The user would then reauthenticate with higher security and therefore obtain access to the requested resource on the resource server that required that higher security.
How can this scenario be achieved?
I do not see anywhere in Spring Security how to easily specify ACR values, or even to trigger re-authnetication of the user.
Checked many many website regarding step-up authentication, adaptive authentication, acr values, etc...
I have developed a set of microservices (resource servers) using Spring Boot 1.5.x + OAuth2 with JWT. Right now each microservice is protected using Spring Security i.e. JWT access token is verified at individual resource server level. API Gateway does not have spring security in place, so it just routes the requests to appropriate server and propagates the authentication headers to downstream services.
I wanted to know if there are any disadvantages of this setup compared to the one where AccessToken is verified at API gateway level only. Or is it just a matter of opinion? Doesn't keeping security at API Gateway level breaks principle of loose coupling, because each microservice may better understand the role of a given user in its own context?
API management can do a small check on your JWT (fail early), BUT your microservices are the only one that can really manage all the security stuff !
If you set security only on api management it means that someone that can access your network will be able to push request to your API unauthenticated.
You will not be able to log who do what. And finally, if you need to set some kind of ACL, it will not be possible (When you ask to list orders, you can only list YOUR order).
Perhaps you will think of decoding your JWT on the api management layers and push a header with user name to your backend to prevent all the thing I spoke about above, but I think it is not really a good practice.
First, access to network will means I'm able to be anybody. Then JWT is much more than just a username. For instance, perhaps you use scope on your authentication layers. ( scope read orders / scope modify orders / scope delete orders). This is useful to restrict what an application can do (either at client_id level) or what a user accept to give to the application ( scope share email ...).
For this JWT on the backoffice is mandatory.
Ok you can do like username and extract data on api management and put specific headers to call backend, but really ? why do specific stuff ? oauth2 with JWT can do this for you.
Well this is an interesting question. In our team we discussed about this topic a lot. Basically you have some parameters affecting the individual answer to this question. But you should always decode and verify granted tokens on the microservice level, too. Because they contain relevant information for authentication and in some cases even for authorization. If your microservices run in a enclosed environment (e.g. on enclosed Kubernetes cluster, where only the API-Gateway is available to the outside) you could use this "mixed" solution.
You can really consider just to verify the AccessToken at the API-Gateway and let the other microservices rely on the API Gateway. The API Gateway could than exchange the AccessToken into another AuthToken, only valid in the microservice-context. This new generated AuthToken can for example contain more sensitive application-bound information, because it is not exposed to the client. The Client gets only a so called opaque token. See https://medium.com/tech-tajawal/microservice-authentication-and-authorization-solutions-e0e5e74b248a
I was getting started with Spring Boot and Angular 7 and I came across user authentication.
Let's assume the following: I have a frontend with Angular 7 and a Backend with Spring Boot that offers API's that can be accessed via HTTP.
So I know that usually the frontend authenticates the user with e.g. JWT that stores all necessary information about the user that might be needed. But I came across the SecurityContextHoler of Spring Boot Security:
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
This allows me to simply access granted Authorities and so on. So I thought about the following:
Using JWT for the frontend grants the following advantages (as far as I know):
* Users can identify when using API's
* Users may be prevented from certain UI-Elements (based on roles stored in JWT)
* Modification prevention due to checksum (invalid token afterwards)
Now I could also add a check in my Controller in the Backend that checks the SecurityContextHolder for user permission (something like a Service that checks the current context permissions vs the needed permission and returns true/false). Wouldn't that be even more save, since it is in the backend (so in my inmagination everything that runs server-sided is always a little more save than what runs client-sided)?
I can store information in the frontend (like roles and a username) to use them for the UI-based-access prevention to still have the same advantages as JWT provides, but I do not have the "effort" of implementing the JWT creation.
But obviously it is not common to do it that way (at least I never saw it), so what is the advantage of the Tokenization?
They are not mutually exclusive. You would use what you call "Tokenized Authentication", like an oAuth2 Bearer token most likely in a JWT when the Authentication is performed by a separate system from your Spring Boot backend. For example, you may be using Okta, Keycloak, Google or Facebook to authenticate the user.
At a minimum, your Spring Boot backend stores the username extracted from the JWT in the Authentication. You can get Spring Boot to extract any roles in the token and add those to Authentication::grantedAuthorites. If your backend system, has it's own set of roles in addition to what's in the token, then the backend could implement a PrincipalExtractor to load a UserDetails object for this user from the database as the Principal and merge the roles in the token with those store in the local database.
You'll probably want to security certain methods in your backend with method security annotations like #PreAuthorize(), since you shouldn't trust the front end. The method security will check permissions, like hasRole("ADMIN") or hasPermission(object, 'READ') using the Principal object in SecurityContextHolder.getContext().getAuthentication();
In the end, the token assures the backend the user accessing it is who they say they are, i.e. Authentication, but does not necessarily tell the backend what they are Authorized to do. Yes, if you control the Authentication server you can include roles in the JWT, but roles don't usually provide as fine a grained control as is required.
Independent of what level of security you implement, the token is translated into an Authorization so you can use the Spring Security framework to manage access within your backend code.
There are 3 type of token in spring security OAuth2:
1. InMemory token Store
2.JWT token store
3.JDBC token store
So now you’re talking the JWT token store. The most powerful of JWT token store is prevent the authorization server load against to the database for checking such as role,token expired so it is related database load performance. Since all the information such as: role,username, token expire ,etc include in token itself. So the authorization server or other resource sever may using the public key to verify this token itself without invoke to data store.
Hope helpful! ☺️
I have a setup with Tivoli Access Manager (TAM) as reverse proxy for some application servers on the backend side. TAM is responsible for authenticating users. Is it possible to access the credentials a user passed in during TAM authentication in the backend applications?
I need this because the backend applications connect to a Host-System and there the credentials are needed to log in.
there are a couple of options you might have for this :
Since you mention TAM, I guess you are still using 6.X, so you can use a custom CDAS (Cross-domain Authentication Service) library. You would need to implement the library yourself in C and handle the authentication part and return the clear text password as an extended entitlement in the credential. This will allow you to add this extended entitlement as an injected HTTP header for the junctions that require the password. You can get more information here : http://www-01.ibm.com/support/knowledgecenter/SSPREK_6.1.0/com.ibm.itame.doc_6.1/am61_web_devref58.htm%23chap-wsd-write-custom
You can implement your own External Authentication Interface. EAIs are external web applications where WebSEAL can delegate the authentication part. In that EAI, as in CDAS, you would have to handle the authentication part yourself - probably against TAM user registry - and then return the clear text password as an extended attribute in the credential to be used as a custom HTTP header for the junction that requires it. See http://www-01.ibm.com/support/knowledgecenter/SSPREK_6.1.0/com.ibm.itame.doc_6.1/am61_web_devref128.htm%23appx-wsd-eai
Leverage Tivoli Federated Identity Manager and a custom STS chain to do the authentication and return the clear text password as part of the credential.
For all 3 of the above options, you would need to modify the existing backend application to read the injected HTTP header and use the clear text password to perform the actions to the Host.
I have done all 3 for various integrations and I think your best choice is writing an EAI, as CDAS got deprecated with ISAM 7 and the 3rd option requires an additional software component.
I am starting a new project where we are planing to build a restful back end and an AJAX font end. I am approaching the problem by focusing on Identifying all the resources that I have and what the various HTTP verbs will do them, their URI and the JSON representations of those resources.
I am looking for the best design for securing the backend. Here is the list of designs I have considered. I am looking for alternative designs not listed below, and pros, cons recommendations. The system will be implemented with Spring 3.0 and possibly Spring Security 3.0, SSL will be used for many parts of the system but not for all of them, so some requests may come on SSL and some might not.
Option 1: Use the HTTP session
Show a standard login screen, create a server side session and let tomcat send back a jsessionid cookie and have the ajax client include the JSESSIONID cookie on every XHR request. This options just feels like it's the wrong approach for the following reasons.
The connection becomes statefull which is against the rules of REST
I want to be able to split the bakcend into multiple seperate WAR files which means i could have multiple HTTP sessions on the backend, if that is the case then this approach does not work. While I don't need the ability to split the backend into multiple apps today, I would prefer a design that allows for that possibility.
Option 2: Find an open source Java based security library that does this
Other than Spring security I have not found any other Java libraries, any recommendations are highly appreciated.
Option 3: Try to use an existing protocol like OAuth
In my very brief look at OAuth it seems that it is designed for authentication across sites where each site has it's own user database. In this system i want a global user database shared across all the backend ajax services.
Option 4: Use SAML and Shiboleth
This options seems over kill and hugely complex to setup and maintain.
Option 5: Send the username and password with every request
This requires that user sends their username and password with every request, which means that the front end AJAX app must store the username and password as a JavaScript object and if the user navigates away from the page then back the username/password combo will be gone and the user might be forced to log in again. I don't want the front end to try and put the username and password into cookie as that would comprise security.
Option 6: Implement my own authentication / Authorization protocol
Create a REST service that users can present their username/password combination to and then get back and security token, which they must send back to the service with every request. The security token would be digitally signed by the service and would have an expiry time. The token would be only good for most operations high security operations would require a new login screen as port of confirming the operation.
Problem with this approach is I have to invent yet another security protocol which seems like a total waste of time.
I am sure I am not the only person up against this problem, I hope the stack overflow community can point to some options and tools that I have not found yet.
Take a look at Apache Shiro. It is an authentication system that has a session management feature that can be used to share sessions across applications. This may be the easiest thing to do.
Or you could use Spring Security (or Shiro) with a Remember Me cookie that is shared across the webapps (as long as they are in the same HTTP domain). The remember me cookie would be analogous to your token in option 6. You can set the expiration on the cookie that so it is short lived like a session cookie or long lived like a regular remember me.
You might also want to take a look at Jasig CAS - Single Sign-On for the Web. It has a REST API and a protocol (Proxy Tickets) that allows services to proxy user AuthN to backend services like you described in option 6. http://www.jasig.org/cas
Briefly...the application that serves up the AJAX client is protected with Spring Security (supports CAS out of the box) and gets a Proxy Granting Ticket that you embed in the AJAX client. The AJAX client uses the PGT to get Proxy Tickets for your REST services...protected with Spring Security too. The REST services get an authenticated userId without every touching primary credentials.
Alternative, you could keep the PGT on the server and use AJAX calls to retrieve Proxy Tickets that are then used by the AJAX client to call you REST services.
As I understood you are going to secure a rest application, to preface you must know that a security provider consisd of three concepts (3A):
-Authentication
-Authorization
-Auditing
to implement these three together you must provide bunch of tools such as :
-SSO provider
-Session Store
-Open Id pattern
-user credentials integration
....
I have used ACL(Spring ACL) to provide authorization services and oauth2 for authentication.
there is one channel to connect these two together and its scopes(oauth2 scopes) but the problem is scopes are not flexible(pure strings) enough to implement authorization modules such as role_voter, cache_strategy, black_list or,Role_base strategy, exceptional permissions, white_list... (but you can use #EnableGlobalMethodSecurity)
In my case I used authorization server as a resource for oauth2 authentication server(take a look at http://projects.spring.io/spring-security-oauth/docs/oauth2.html), then I considered two spots to check authorization, the first I issued ACL to front-end and forced programmer to design her page dynamically up to ACL concept, the second is in back-end on service layer(BLL) using Aspect when one rest is going to be called. I sent the service key as an actee to check if current user has enough access control to do that. and for auditing you must monitor all requests I mean you must use an listener in your gateway or broker...