Store tokens to access other applications on Spring Boot - spring-boot

I have a rest application in Spring Boot, with security configured and JWT tokens implemented for the services it exposes. But this application also connects to other 3rd party applications, also secured with JWT and with different tokens per application.
My question is: what is the best strategy to store these 3rd party tokens? Is there something like SecurityContextHolder, but for storing the tokens that the application uses to authenticate on other services?

While configuring your
OAuth2RestOperations restTemplate
You can persist the token in the client
public OAuth2RestOperations restTemplate() {
OAuth2RestTemplate template = new OAuth2RestTemplate(resource(), new
DefaultOAuth2ClientContext(accessTokenRequest));
AccessTokenProviderChain provider = new
AccessTokenProviderChain(Arrays.asList(new AuthorizationCodeAccessTokenProvider()));
provider.setClientTokenServices(clientTokenServices());
return template;
}
As described by in spring security oauth docs here
Persisting Tokens in a Client
A client does not need to persist tokens, but it can be nice for users to not be required to approve a new token grant every time the client app is restarted. The ClientTokenServices interface defines the operations that are necessary to persist OAuth 2.0 tokens for specific users. There is a JDBC implementation provided, but you can if you prefer implement your own service for storing the access tokens and associated authentication instances in a persistent database. If you want to use this feature you need provide a specially configured TokenProvider to the OAuth2RestTemplate

Related

Spring Cloud - Micoservice Authentication propagation

I am building an application using microservice architecture. I am using Eureka for service discovery with Spring Cloud Gateway for request routing. For authentication mechanism I am issuing JWT tokens (in auth service). What is the best practice when it comes to propagating Authentication so I can get logged user information in each service which is after the gateway?
So far I've came up/found couple of possible solutions:
In gateway add headers for relevant user information, and in each service create filter which would take said headers and create Authentication object and store it into SecurityContextHolder. The downside of this approach is I can't just plug and play services outside my application.
Pass the token coming from the client through the gateway to the each service, where I would have JWTFilter which would validate token and extract the user information. Downside I see with this approach is I have to have jwt secret shared between each service or stored on each service, and I would have to implement JWT logic, producing duplicate code.
Final solution is having something like oAuth token introspection endpoint in auth service which would be called from each service (filter) once the request reaches it.
I implemented the filter logic for validating the user token in the gateway service, but I would like to use role based authorization on each endpoint (service) differently (ie. user service has endpoint for creating users (ADMIN), and for fetching user information (ANY ROLE)).
I opted for something like your option 2 and use spring-boot to configure JWT decoder from an OIDC authorization-server (Keycloak).
Configuring OpenID resource-servers is super easy (more options in parent folder), and authorization-server JWT public signing key is retrieved automatically by spring JWT decoder.
All that is required is ensuring that Authorization header with JWT bearer is correctly propagated between services.

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.

Keycloak multi-tenancy and bearer-only microservice

I have some Spring Boot microservices with Spring Cloud API gateway (Zuul) in front of them.
API gateway authenticates users and forward the Authorization bearer token header.
Working fine with a single realm.
Now, I'd like to use multiple realms.
Using KeycloakConfigResolver, I'm able to authenticate user with the API gateway (keycloak deployment based on path).
But how should I configure KeycloakConfigResolver for microservices (bearer-only) so the use the right KeycloakDeployment? As every service can be accessed by both realms I don't know how to detect against which realm user was authenticated?
I cannot use path for KeycloakConfigResolver as for example for the order-service, users can do a GET on /orders being authenticated by realm1 or realm2...
Using header does not seem to be a good solution either....
Any idea?
I hope I'm clear enough...
You can find the realm from the KeycloakPrincipal (logged-in user) and then build KeycloakDeployment accordingly, you find the example here
InputStream is = getClass().getResourceAsStream("/realm1-keycloak.json");
KeycloakDeployment deployment = KeycloakDeploymentBuilder.build(is);

Spring Security custom validation without using user password involved

I was wondering if in Spring Security is possible to lock all endpoints of a rest api, and to do a login by doing a custom validation without using the username and password at all.
It is like create a custom validation method that receives a token and not user/pass. The method will then validate the token with third party that has already validated the caller.
This sounds familiar to OAuth2 only that the backend API needs to be secure by spring, and at the same time it is not the OAuth2 client:
We are building a login feature.
We have a client (mobile app), backend (REST like endpoints Spring MVC), and an AuthProvider for OAuth2/OpenIdConnect flows.
The OAuth/OpenIDConnect flow happens only between the mobile and OpenIDProvider. (an initial call happens from mobile to backend to provide some details for oauth flows)
Once the authorization succeeded, the mobile app receives an auth_code, and only then the backend is called from the app to "Login" which means validate the auth_code, exchange for access_token, and create user session. (we need to have a session).
As you see backend kind of "login" in the sense that needs to receive the auth_code only, and validate it with the AuthProvider before creating a session.
Thank you very much!
Any comments, or references are very appreciated.
Spring Security determines if a user is authenticated by looking at the SecurityContext in the SecurityContextHolder. This means you can authenticate the user however you like using the following:
boolean userIsAuthenticated = ...
if(userIsAuthenticated) {
Authentication request = new UsernamePasswordAuthenticationToken(name, password);
Authentication result = ...
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(result);
SecurityContextHolder.setContext(context);
}
Spring Security is a very flexible framework that publishes a variety of interfaces that allow the user to customize the behavior as need be.
I'd recommend the following resources to learn how to go about this:
Architecture Deep Dive in Spring Security
Spring Security Custom Authentication Provider
Spring Security Custom AccessDecisionVoters
Spring Security Reference Documentation

Accessing Tenant Information with Spring OAuth2

I have an application that needs to pull tenant information on a per method basis. I am using Cloud Foundry's UAA server for my Authentication and Authorization needs. I have tried to access tenant information by doing the following:
#RequestMapping("/")
#PreAuthorize("#oauth2.hasScope('project.retrieveItems')")
public List<ItemDto> retrieveAll(OAuth2Authentication token) {
... Code here to retrieve Identity Zone and use it to filter results.
}
The OAuth2Authentication object doesn't have any information about the Tenant, only the scopes and authorizations. Is there anyway to get this information from a method?
Thanks for any assistance.
IdentityZoneHolder.get()
will return the current tenant that is being accessed within the UAA (if you're coding within the UAA itself)
But I take it that you are asking about your application, the core Spring Security Oauth2 implementation has no idea about tenants
It only has awareness of a token url and a check token url.

Resources