Spring Boot Keycloak Adapter extract roles from custom field in JWT token - spring

I'm using Spring Boot Keycloak Adapter in my backend application.
It has properties for extracting roles from JWT token:
keycloak:
use-resource-roles-mapping: true
If this option is set to true, then the toles of user will be extracted from token from the field resource_access.roles[]
If this option is set to false, then the roles of user will be extracted from token from the field realm_access.roles[]
But I have roles in my token in another field, roles[] are placed in root directly, without wrappers resource_access or realm_access
As I see, Keycloak adapter does not allow to customize the behaviour of extracting roles from token.
So, the question is, how do I ovveride this behaviour to extract roles from token from the field I want?

Actually, client roles are held in resource_access.{client-id}.roles, (not resource_access.roles).
Keycloak adapters were deprecated a year ago and are not compatible with spring-boot 3. Just don't use it.
You can refer to the accepted answer to "Use Keycloak Spring Adapter with Spring Boot 3" for alternatives. The solution exposed there works for spring-boot pulling versions of spring-security with SecurityFilterChain (boot 2.4 or so) with almost no modification (just a few configuration methods have been renamed in spring-security 6 (boot 3) to align reactive and servlet DSLs).
You should read the part of the answer with "my" starters which enable to configure role mapping from application.properties (or yaml): source claims (not just one claim at a time, but as many as you need), prefix and case transformation. All that for each issuer (possible to accept identities from as many realms, Keycloak instance or even from other OIDC authorization-servers than Keycloak).

Related

Why do we need Keycloak permissions/policies/scopes if we want to control access on the backend?

I'm still not able to understand the purpose of keycloak permissions/scopes/policies if we still validate user per resource based on the role of the user.
I use Spring Boot and all the documentations shows that role must be included in the configuration:
...
.antMatchers("/api/account").hasRole("account")
.anyRequest()
.authenticated();
We have configured the above policy in the keycloak but on the backend we again check the user role. Why do we need keycloak policy configuration?
In keycloak, we can create authorization scopes. How can I use that scope to protect my api based on this scopes?
I couldn't find a way to add authorization scopes into JWT token but keycloak provides UMA endpoints to fetch scopes, but would it be correct way to implement?
By default, spring-security is based on user "granted authorities" (in spring world, roles are just authorities with ROLE_ prefix). Spring-boot default configuration for JWT turns scopes into authorities.
But you might use SpEL in #PreAuthorize() or #PostAuthrize() and write security rules involving more than just user authorities. See for instance this expression taken from here:
#PreAuthorize("is(#grantingUsername) or hasAuthority('USERS_ADMIN') or onBehalfOf(#grantingUsername).can('PROXIES_EDIT')")
It checks user either:
is "granting user": username retrieved from JWT token equals grantingUsername path variable
is granted with USER_ADMIN authority
was granted with PROXIES_EDIT permission by "granting user"
You can write about anything with security SpEL, based on security-context (Authentication instance created from access-token JWT) and annotated method parameters or returned value.
OpenID standard only defines how resource-owners identity must be presented. It contains nothing specific about permissions.
As so, each authorization-server is using its own private-claims for permissions (roles, resource-access, etc.).
By default, Keycloak exposes realm roles in realm_access.roles claim. You can also add user roles specific to a client with client roles mapper (in admin console: clients -> some-client -> mappers and then click Add Builtin button). This will put client roles in a claim like resource_access.some-client.roles. You can also write your own mappers to feed any claim with what you need (I wrote such a mapper here). But all this is very Keycloak specific.
If you already defined user roles (or whatever your security rules are based on) in Keycloak, you should find it in JWT access-tokens (open it in a tool like https://jwt.io to check). If so, all you need to do is replace Spring default JwtGrantedAuthoritiesConverter (which converts scopes to authorities) with a converter extracting authorities from Keycloak specific claims for roles.
You could also use libs I wrote for spring-boot OpenID resource-servers.
Please refer to tutorials in this repo to get started. resource-server_with_oauthentication can provide you with a resource-server with role based access control in 5 minutes (including security rules unit-tests).
If you want to do something else than role-based access control, you'll have to override more #Beans and spring-security components. You could start with this advanced tutorials or the api module of the complete application from which I took security expression above.

How to implement JWT with Keycloak in Spring boot microservice acrhitecture?

I have read some articles for Keycloak spring implementation (eg: easily-secure-your-spring-boot-applications-with-keycloak) but no one mention how to use with JWT.
I have created zuul api gateway and add Keycloak adapter as described in the previously linked article. That's ok, but I want to use JWT with keycloak.
Mentioned elsewhere set the client access type to bearer-only and the session strategy to NullAuthenticatedSessionStrategy. That's enough or need something else for JWT?
So my questions:
How do I configure client on Keycloak admin for JWT?
How do I configure Keycloak in backend config file for JWT?
How do I configure Keycloak adapter for JWT?
How do I pass user info to microservice? Create filter in gateway? But how I get user info from request?
Keycloak access token is a JWT. It is a JSON and each field in that JSON is called a claim. By default, logged in username is returned in a claim named “preferred_username” in access token. Spring Security OAuth2 Resource Server expects username in a claim named “user_name”. So, you need to create mapper to map logged in username to a new claim named user_name.
In order to provide access to client (micro-service), respective role needs to be assigned/mapped to user.
In your spring boot application, then you need to configure connection to keycloak server, providing, auth url, token url, scope, grant-type, client-id and client-secret.
Afterthat, your app be able to parse JWT token, you need to create some JwtAccessTokenCustomizer. This class should extend DefaultAccessTokenConverter and implement JwtAccessTokenConverterConfigurer classes. The main logic lays in public OAuth2Authentication extractAuthentication(Map<String, ?> tokenMap) method.
Then you need to configure OAuth2 Resource Server to provide access for other micro services. For that you define here - Oauth2RestTemplate Bean.
And in the end, secure your REST API, via the standard configuration Component.
So, you can see that, it is a large work, and couldn't be described with code, show some of your work, divide it to the chunk, and ask interesting your questions.

I would like to integrate Keycloak with Spring Boot 2 and Swagger

Now, I use Spring boot version 2.0.0.RELEASE and Swagger version 3.1.6 and Keycloak of Jboss. I would like to know how to configure in application.yml then let swagger can get access_token from Keycloak.
Thanks for your help
An initial decision to make is whether to say that the user accessing the swagger page needs to have an access token (i.e. the url pattern for swagger is secured and the user has to log in to get to swagger) or you exclude the swagger URLs from keycloak so that its UI can be accessed without needing a token.
If you're using the keycloak spring boot adapter then the URL patterns to secure (and which roles are required to access them) are configured in the application.yml or application.properties file as security-constraints. As properties an example is:
keycloak.security-constraints[0].authRoles[0]=user
keycloak.security-constraints[0].securityCollections[0].patterns[0]=/customers/*
This could be translated to yaml as:
keycloak:
security-constraints[0]:
-authRoles[0]: user
-securityCollections[0]:
-patterns[0]: /customers/*
(Real yml example at https://github.com/codemonkeybr/skip/blob/master/skip-cart/src/main/resources/application.yml#L29 )
Anything not covered by security-constraints is not restricted. There's a similar way of doing this with spring security if you're not using the official keycloak adpater - normally then you do it in a SecurityConfiguration java class.
Then you face decisions based on your chosen oauth2 flow and whether you use the 'try it out' feature. You can display descriptions without necessarily needing a token but 'try it out' does need a token. That yaml example above also has a way of telling swagger the token issuer url:
swagger:
auth:
token-url: ${keycloak.auth-server-url}/realms/${keycloak.realm}/protocol/openid-connect/token/
client-id: skip-local
That config is read by a java swagger configuration class and is part of a whole example that you could run. This specific question of how to configure swagger to work with an oauth2 token is not specific to keycloak and is general swagger-oauth2 configuration for which there is a guide at baeldung and there's an example using a different mode in Keycloak integration in Swagger

spring security spnego ldap jwt

I have a complex situation where I need to implement a security for web app on tomcat 8 that serve both static html and rest services. the app is spring mvc application (no spring boot)
the authntication ( sso ) process will go as follow:
if user jwt not exist in http header then authonticate with ldap, getting user authorities from db and create jwt back to user.
if jwt exist in header, skip ldap filtering , extract the user authorities from token.
I was thinking of first servlet filter that uses spnego library and get the windows domain name (user name to use in ldap) that filter will also check to see if ldap authontication is needed ( if token not provided) and pass it back to spring filter chine through http params..
I'm struggling to implement he ideal.
please help.
thanks
As I know, there is support for LDAP in spring security, might be it will help you.
Other than that, if you want to write your own filters then you have to add those in spring security filter chain.

how to implement single sign-on for multiple Web applications based on JAAS(Authorization)

I started working on JAAS with SSO,I have some doubt about JAAS. JAAS (Java Authentication and Authorization Service) framework to cater to multiple authentication mechanisms. The SSO server validates sign-on information against its own database or an external directory server and returns the session context and list of applications that the signed-on user can execute.Here i want to implement one more web application's.As per my knowledge the SSO JAAS will return Session context. In my client web applications already, i have acegi security for authentication, using my acegi security how can i get the session context from my SSO JAAS for Authorization.I am trying to find out any configuration sample , but still I did't get any work around example.
Take a look at this spring security configuration. It is not exactly what you want but it will show you the way
Key points
Check how authentication-manager is defined by using
PreAuthenticatedAuthenticationProvider. The preAuthenticatedUserDetailsService property defines a bean that will allow you to create your spring security UserDetails object from the JAAS Authentication object
The j2eePreAuthFilter filter is the one that will delegate security from JAAS to spring security.
The rest is standard spring security configuration
Hope it helps a bit

Resources