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

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.

Related

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

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).

Add additional inner user validation after successful OAuth2 Resource Server JWT check at Keycloak

There is a Spring boot app with endpoints protected with JWT. Token validation is performed by Spring boot OAuth2 Resource Server that checks tokens at Keycloak Authorization Server.
How can additional inner user validation be added to the app after it successfully passes authorization at Keycloak?
So I'd like to build some kind of a chain - if token passes validation at Auth Server then I check the username taken from JWT at local database.
Checking access-token claims against local database for access-control on a resource-server is an easy task inside authentication converters (http.oauth2ResourceServer().jwt().jwtAuthenticationConverter(...) or http.oauth2ResourceServer().opaqueToken().authenticationConverter(...), but this is very inefficient: it is much better to have this DB access once when the token is created on authorization-server, rather than each time it is evaluated during resource-server authorization process (which happens for each request).
All the data required for access-control decisions should be included in the token already. If you need more than standard claims plus the default private claims from your authorization-server, then configure this authorization-server to add the data you need about the user when issuing access-tokens. For Keycloak, this is done with so called "OIDC protocol mappers". Those can issue DB requests, web-service calls and about anything. I have a sample of a mapper adding a private claim with a value from a web-service call in this project.
Once all the data you need is in the token, you just use it as normal in Spring security expressions of your resource-server. Here is a working sample taken from my set of tutorials:
#PreAuthorize("is(#username) or isNice() or onBehalfOf(#username).can('greet')")
In this expression, it is checked that the user either:
is greeting himself (username #PathVariable is equal to preferred_username claim in access-token)
has one of "nice" roles
has permission to greet on behalf of user with preferred_username equal to username #PathVariable (the route is /greet/{username} and this permissions delegation is taken from a private claim added by a mapper like the one in the sample linked above)

custom oidc in keycloak

I have a spring based application which does authentication and authorization(oauth2 based) for a client app.I want to now use keycloak to manage my authorizations, but i want to keep my spring code. Basically i want to use my existing auth code as an external identity provider in keycloak.
I am thinking of adding changes in client app such that it receives token from my existing oauth code(which does the authentication) and then exchange this token with keycloak(for session and authorization management). How can i do this? What configurations need to be done in keycloak?
I read about token exchange in keycloak here, but i am not clear about the kind of token i need to send from my existing auth code.
https://www.keycloak.org/docs/latest/securing_apps/
Here is how OAuth2 roles are usually spread:
Keycloak is authorization-server
Spring service is resource-server
front-end is client
user is resource-owner
I have a doubt of you wanting your Spring service to be "authorization-server" as well (serve user identity). If so, I think you should not.
Keycloak (or any other OpenID provider) should be the only authorization-server. Both Spring and client(s) should be configured to use it as so.
To write it differently, Keycloak is responsible for users login and emitting tokens with user ID (subject) and rights (roles or whatever). Other tiers in the architecture (clients & resource servers) get user info from the token and apply relevant security checks (spring security annotations, Angular guards, etc.).
I published a mono-repo for a meetup with minimal sample involving a Spring resource-server and Angular (with Ionic) client talking to a Keycloak OpenID authorization-server. You might find some inspiration browsing it.

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.

How to provide security for the password using spring

I am new to spring. My requirement is:
I need to get the user name and password in my component class. validate it with by invoking the webservices available at my client.
So I want to provide security to my password which can not be directly visible anywhere.
So how to implement this?
Please give suggestions
Spring Security can participate in many different authentication environments. While we recommend people use Spring Security for authentication and not integrate with existing Container Managed Authentication, it is nevertheless supported - as is integrating with your own proprietary authentication system.
What is authentication in Spring Security?
Let's consider a standard authentication scenario that everyone is familiar with.
A user is prompted to log in with a username and password.
The system (successfully) verifies that the password is correct for the username.
The context information for that user is obtained (their list of roles and so on).
A security context is established for the user
The user proceeds, potentially to perform some operation which is potentially protected by an access control mechanism which checks the required permissions for the operation against the current security context information.
The first three items constitute the authentication process so we'll take a look at how these take place within Spring Security.
The username and password are obtained and combined into an instance of UsernamePasswordAuthenticationToken (an instance of the Authentication interface, which we saw earlier).
The token is passed to an instance of AuthenticationManager for validation.
The AuthenticationManager returns a fully populated Authentication instance on successful authentication.
The security context is established by calling SecurityContextHolder.getContext().setAuthentication(...), passing in the returned authentication object.
This could help: http://www.viddler.com/v/c596114a

Resources