I have a Spring Boot microservice application generated using JHipster with Keycloak. Below are the versions for the application:
- JHipster - 7.9.3
- Spring Boot - 3.0.2
- Spring Cloud - 2022.0.1
- Keycloak - 20.0.3
I had manually updated the Spring Boot version from the one generated by JHipster.
The security configuration is as follows:
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Import(SecurityProblemSupport.class)
public class SecurityConfiguration {
private final JHipsterProperties jHipsterProperties;
@Value("${spring.security.oauth2.client.provider.oidc.issuer-uri}")
private String issuerUri;
private final SecurityProblemSupport problemSupport;
public SecurityConfiguration(JHipsterProperties jHipsterProperties, SecurityProblemSupport problemSupport) {
this.problemSupport = problemSupport;
this.jHipsterProperties = jHipsterProperties;
}
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off
http
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(problemSupport)
.accessDeniedHandler(problemSupport)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeHttpRequests()
.requestMatchers("/api/authenticate").permitAll()
.requestMatchers("/api/auth-info").permitAll()
.requestMatchers("/api/admin/**").hasAuthority(AuthoritiesConstants.ADMIN)
.requestMatchers("/api/**").authenticated()
.requestMatchers("/management/health").permitAll()
.requestMatchers("/management/health/**").permitAll()
.requestMatchers("/management/info").permitAll()
.requestMatchers("/management/prometheus").permitAll()
.requestMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
.and()
.oauth2ResourceServer()
.jwt()
.jwtAuthenticationConverter(authenticationConverter())
.and()
.and()
.oauth2Client();
return http.build();
// @formatter:on
}
Converter<Jwt, AbstractAuthenticationToken> authenticationConverter() {
JwtAuthenticationConverter jwtAuthenticationConverter = new JwtAuthenticationConverter();
jwtAuthenticationConverter.setJwtGrantedAuthoritiesConverter(new JwtGrantedAuthorityConverter());
return jwtAuthenticationConverter;
}
@Bean
JwtDecoder jwtDecoder() {
NimbusJwtDecoder jwtDecoder = JwtDecoders.fromOidcIssuerLocation(issuerUri);
OAuth2TokenValidator<Jwt> audienceValidator = new AudienceValidator(jHipsterProperties.getSecurity().getOauth2().getAudience());
OAuth2TokenValidator<Jwt> withIssuer = JwtValidators.createDefaultWithIssuer(issuerUri);
OAuth2TokenValidator<Jwt> withAudience = new DelegatingOAuth2TokenValidator<>(withIssuer, audienceValidator);
jwtDecoder.setJwtValidator(withAudience);
return jwtDecoder;
}
}
The security related application properties are:
spring:
security:
oauth2:
resource:
filter-order: 3
client:
provider:
oidc:
issuer-uri: http://localhost:8080/realms/samplerealm
registration:
oidc:
authorization-grant-type: client_credentials
client-id: microservice-client
client-secret: <VALID_CLIENT_SECRET>
scope: openid, profile, email, offline_access # last one for refresh tokens
With these configurations, the application is listening on localhost:8087 for HTTP requests.
I created another client in Keycloak dev-client and using Postman to test the application API. I acquired an access token from Keycloak using this client and used the access token in Postman in the Authorization header (Bearer ----access token----). Even with this valid token, the API forwards me to localhost:8087/login with an HTML page response:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="">
<meta name="author" content="">
<title>Please sign in</title>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
<link href="https://getbootstrap.com/docs/4.0/examples/signin/signin.css" rel="stylesheet"
crossorigin="anonymous" />
</head>
<body>
<div class="container">
<h2 class="form-signin-heading">Login with OAuth 2.0</h2>
<table class="table table-striped">
</table>
</div>
</body>
</html>
Here is a snapshot of Postman console (the snapshot is cropped because of the length of the access token)
I am not sure why are the requests being redirected/forwarded to localhost:8087/login even if I have provided a valid access token. I have tried poviding an access token which is acquired using password grant with a different client but it still gave me the same result.
Any HTTP requests to the application gets forwarded to localhost:8087/login, so far I tried GET request and it is throwing me this issue.
