How to validate a token from a OAuth server? - spring-boot

I created a Spring Boot application where I have the authorization and resource server, this is my main class:
#SpringBootApplication
#EnableResourceServer
#EnableAuthorizationServer
public class OauthServerApplication {
public static void main(String[] args) {
SpringApplication.run(OauthServerApplication.class, args);
}
}
And this is my application.yml:
security:
user:
name: guest
password: guest123
oauth2:
client:
client-id: trustedclient
client-secret: trustedclient123
authorized-grant-types: authorization_code,refresh_token,password
scope: openid
To generate the access token I only execute this url (POST):
http://trustedclient:trustedclient123#localhost:8080/oauth/token?username=guest&password=guest123&grant_type=password
It returns:
{
"access_token": "f2e722b7-3807-4a27-9281-5b28b7bd3d0d",
"token_type": "bearer",
"refresh_token": "f96d472c-8259-42e2-b939-4963dfeeb086",
"scope": "openid"
}
Now I need to know how to validate if the token is correct, any help?

You have multiple possibilities, you can:
1) Store the token in a TokenStore and open a secured validate token enpoint on the authorization server for the resource server.
2) If the authorization server and the resource server can share a DataSource, (in your case it's easy because both are in the same application). They can both use a JdbcTokenStore pointing to the same database and the resource server can directly check the validity of a token in this token store. See this tutorial : Spring REST API + OAuth2 + AngularJS
3) You can use signed JWT tokens with JwtTokenStore and JwtAccessTokenConverter. See this tutorial : Using JWT with Spring Security OAuth
Both of these tutorials are based on the following github repository : https://github.com/Baeldung/spring-security-oauth

To validate the token I typically make a request for the /user using access token in the Authorization header.
In the Spring Oauth server I add the following endpoint.
#GetMapping("/user")
public Principal user(Principal user) {
return user;
}
And this would be the request sent to it.
GET http://localhost:8443/v1/auth/user
Authorization: Bearer some-access-token
This has the added benefit of returning the user object, which is typically needed. So kill two birds with one stone.

Related

Spring Cloud Gateway Oauth2Login Return JWT Token Instead of SESSION Cookie Upon Successful Login

sorry in advance if the question is previously asked, but I have not been able to find an answer.
I am trying to setup Spring Cloud Gateway to act as a OAuth2 client to authenticate/login users via a Keycloak Authentication server. I have been able to achieve this using the following code snipet:
Security Config:
#Configuration
#EnableWebFluxSecurity
#EnableReactiveMethodSecurity
public class SecurityConfig {
private final GatewayAuthenticationSuccessHandler gatewayAuthenticationSuccessHandler;
public SecurityConfig(GatewayAuthenticationSuccessHandler gatewayAuthenticationSuccessHandler) {
this.gatewayAuthenticationSuccessHandler = gatewayAuthenticationSuccessHandler;
}
#Bean
public SecurityWebFilterChain securityWebFilterChain(
ServerHttpSecurity http,
ReactiveClientRegistrationRepository clientRegistrationRepository) {
http
.authorizeExchange()
.pathMatchers("/ui/**").permitAll()
.anyExchange().authenticated()
.and()
.oauth2Login().authenticationSuccessHandler(gatewayAuthenticationSuccessHandler)
.and()
.oauth2ResourceServer().jwt();
http.logout(
logout ->
logout.logoutSuccessHandler(
new OidcClientInitiatedServerLogoutSuccessHandler(clientRegistrationRepository)));
http.logout().logoutUrl("/logout");
http.csrf().disable();
http.httpBasic().disable();
http.formLogin().disable();
return http.build();
}
}
Auth Success Handler:
#Component
public class GatewayAuthenticationSuccessHandler implements ServerAuthenticationSuccessHandler {
private ServerRedirectStrategy redirectStrategy = new DefaultServerRedirectStrategy();
#Value("${my.frontend_url}")
private String DEFAULT_LOGIN_SUCCESS_URL;
#Override
public Mono<Void> onAuthenticationSuccess(WebFilterExchange webFilterExchange, Authentication authentication) {
URI url = URI.create(DEFAULT_LOGIN_SUCCESS_URL);
return this.redirectStrategy.sendRedirect(webFilterExchange.getExchange(), url);
}
}
With this setup, the gateway app can authenticate the users and obtain a JWT token from the authentication server on behalf of the caller (UI app). Based on my understanding, Spring security then uses spring session to create and feed back a SESSION cookie to the caller. This session cookie can be used for subsequent calls to authenticate the user. The gateway would use the SESSION cookie value to retrieve the associated JWT token from the cache and relays it to the downstream resource servers when proxying requests. I have also setup a token refresh filter to refresh the JWT token on the caller's behalf and a Redis ache to share this session cookie between multiple instances of the gateway.
What I would like to do now is to return the actual JWT token that was retrieved by the gateway back to the caller (instead of a SESSION cookie). In other words I am hoping to make my gateway a little more stateless by using JWT end-to-end (instead of using SESSION cookie for caller --> gateway and then JWT for gateway --> resource servers). Is this even possible with the current state of spring cloud gateway?
PS. I am using spring boot version 2.2.8 and spring cloud version HOXTON.SR6
Not sure this can help , but try to add a SessionPolicy as STATELESS to your webfilter chain as shown below , and it should work.
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
Also you could try to override the sessionAuthenticationStrategy with a NullAuthenticatedSessionStrategy if you are extending your config class to WebSecurityConfigurerAdapter.
override fun sessionAuthenticationStrategy(): SessionAuthenticationStrategy {
return NullAuthenticatedSessionStrategy()
}

How to define a custom grant type in a Spring Security Oauth2 client?

I have a working api-gateway application built on spring-boot 2.2, which is an Oauth2 client supporting authorization-code grant flow. It is built using spring-boot #EnableOAuth2Sso, which will create a spring session and oauth2 context once the user is successfully logs in. Every request to the resource server will be intercepted by this api-gateway, and validates the user session also the oauth2 token from the session context. All the resource servers are Oauth2 protected.
I need to support SAML2 login also through this gateway. I have setup WSO2 as Identity provider, which provides the SAML response as a POST request to an endpoint in the api-gateway once a user is successfully logged in through an IDP initiated login flow. Right now the WSO2 IDP is able to provide me an Oauth2 token when I submit a token request with SAML assertion and SAML grant type. What I need is when a SAML POST request comes from the WSO2 IDP to the api-gateway, it should create an Oauth2 token from WSO2 using SAML assertion and SAML grant type, also should create a Spring session and Oauth2 context with this received Oauth2 token.
I have two possible options at this moment,
1) Define a custom spring security Oauth2 grant-type in the api-gateway Oauth2 client, and handle the SAML response to generate Oauth2 token using spring-security, also the Spring session and Oauth2 context.
2) Manually write code to generate Oauth2 token using SAML response, also manually create a new Spring session and Oauth2 context, which will be an ugly approach.
Given below the current security configuration class.
#Configuration
#EnableOAuth2Sso
public class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
private static final String ROOT_PATH = "/";
private static final String SUFFIX = "**";
private static final String ANY_OTHER = "/webjars";
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher(ROOT_PATH + SUFFIX)
.authorizeRequests()
.antMatchers(LOGIN_PATH.value() + SUFFIX, ERROR_PATH.value() + SUFFIX, ANY_OTHER + SUFFIX, "/saml**").permitAll()
.antMatchers(HttpMethod.POST, "/saml**").permitAll()
.anyRequest()
.authenticated()
.and().csrf().ignoringAntMatchers("/saml**")
.and().logout().logoutSuccessUrl(LOGOUT_SUCCESS_PATH.value()).permitAll();
}
#Bean
public OAuth2RestOperations restTemplate(OAuth2ClientContext clientContext, OAuth2ProtectedResourceDetails resourceDetails) {
return new OAuth2RestTemplate(resourceDetails, clientContext);
}
#SuppressWarnings({ "rawtypes", "unchecked" })
#Bean
public FilterRegistrationBean oauth2ClientFilterRedirectRegistration(OAuth2ClientContextFilter filter) {
FilterRegistrationBean registration = new FilterRegistrationBean();
registration.setFilter(filter);
registration.setOrder(-100);
return registration;
}
}
The Yml configuration is given below
security:
basic:
enabled: false
oauth2:
client:
clientId: xxxx
clientSecret: xxxxx
accessTokenUri: http://localhost:9763/oauth2/token
userAuthorizationUri: http://localhost:9763/oauth2/authorize
scope: openid,email,name
resource:
userInfoUri: http://localhost:9763/oauth2/userinfo
jwk:
key-set-uri: http://localhost:9763/oauth2/jwks
Can someone suggest how we can define a custom spring security Oauth2 grant-type in a Oauth2 client? Is there any documentation available to configure the same? Does the spring-security support this requirement?
Also is there any other solutions to handle this scenario? Any suggestions please.

spring OAuth2 service to service client credentials

I have a set of services behind a zuul gateway, one of which is the auth server. I have it configured to parse the jwt with a jwk set from the auth server at /.well-known/jwks.json for users on each service with a password grant to access simple endpoints, but i'm wondering if it's possible to decide on a case by case basis which controllers and endpoints are using the user's access token vs using the service's client credentials when those services have to call other services. for example:
I have a contact service that manages customers, and another service that manages inventory.
When a user wants to see which customers are interacting with which inventory, i'm able to use an OAuth2RestTemplate to call the other service like so
#RequestMapping("/sales/{id}")
public Map<Object, Customer> getSales(#PathVariable Long customerId) {
Object inventory = restTemplate.getForObject("http://inventory-service/inventory", Object.class);
Customer customer = repository.findById(customerId);
Map<Object, Customer> sales = new HashMap;
sales.put(customer, inventory);
return sales;
}
I'm getting a 500 response A redirect is required to get the users approval even though i've tried configuring the Customer service to use client credentials flow instead of authorization code flow.
the security settings for the customer service:
security:
oauth2:
resource:
jwk:
key-set-uri: ${GATEWAY:http://localhost:8762}/.well-known/jwks.json
client:
client-id: first-client
client-secret: noonewilleverguess
access-token-uri: ${GATEWAY:http://localhost:8762}/oauth/token
with the main class annotated with #SpringBootApplication, #EnableGlobalMethodSecurity(prePostEnabled = true), and #EnableResourceServer.
here's some more configuration for context
#EnableWebSecurity
public class SecurityConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().anyRequest().permitAll();
}
#LoadBalanced
#Bean
public OAuth2RestTemplate restTemplate(OAuth2ClientContext clientContext,
OAuth2ProtectedResourceDetails resourceDetails) {
return new OAuth2RestTemplate(resourceDetails, clientContext);
}
the documentation suggests that #EnableOAuth2Client isn't necessary when exposing the OAuth2RestTemplate so i have omitted that annotation.
Ideally i'd like to be able to pick and choose which requests use the user's access token and which requests use the service's client credentials, but i haven't found any resources that do so. Is it even possible?

How to do LDAP authentication on Post Request

For my application, I use Spring boot and LDAP to authentication user. And I have Spring Security to control the API.
Basically what I do is to attach the Authentication: basic on the header and call the get user api(/user, get mapping) to get the user details. From there I return the pricinpal and use the user session to access the application.
#GetMapping("/user")
public Principal user(Principal user) {
return user;
}
My question is how to do authencation on post? Same header with authentication, but the only difference is /user endpoint will be post mapping. From postman I got 401 error. Somehow LDAP isn't picking up the authentication header to do authentication.
#PostMapping("/user")
public Principal user(Principal user) {
return user;
}
Please Help. And Thanks in advance.

How to have Spring Security enabled for an application using third party login?

I have a Spring Boot enabled application whose login is controlled by third party Siteminder application. After successful authentication, Sitemeinder redirects to our application url. We fetch the HttpRequest from Siteminder and process the requests.
Now, how can Spring security be enabled in this case for authorizing users based on roles.
#Controller
public class LoginController
#RequestMapping( value= "/")
public void requestProcessor(HttpServletRequest request)
{
.
.
.}
The above controller's request mapper reads the request coming from SiteMinder and processes the request which has the Role of the user logged in. Where can we have Spring Security enabled to authorize pages and service methods to the user.
This is an scenario for the PreAuthenticated security classes:
Take a look here:
http://docs.spring.io/spring-security/site/docs/current/reference/html/preauth.html
Spring Security processes request before it gets to your controller in a filter configured in spring security configuration.
There is a documentation on how to configure spring security with SiteMinder.
The rules in your configuration will define the access to resources
Depends what you get in session. If somehow u can to take user and password from session you can authenticate user directly from code as :
#Autowired
AuthenticationManager authenticationManager;
...
public boolean autoLogin(String username, String password) {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
Authentication auth = authenticationManager.authenticate(token);
if (auth.isAuthenticated()) {
logger.debug("Succeed to auth user: " + username);
SecurityContextHolder.getContext().setAuthentication(auth);
return true;
}
return false;
}

Resources