I am using Keycloak
in my REST
application with spring-boot
.
It works correctly, I have defined roles
in Keycloak
, then in my Config.class I allow access to the end-points that interest me according to the role of each user. I have the problem when trying to retrieve the user information in my back (name, principal, authorities...).
I have read various SO
POSTS like these:
how-to-get-principal-from-a-keycloak-secured-spring-boot-application
nullpointer-when-securing-spring-boot-rest-service-with-keycloak
but I can't find any that work for me. If I use SecurityContext
or KeycloakAuthenticationToken
, I get null when calling the getAuthentication method.
In my code, in Controller class I have the following:
private SecurityContext securityContext = SecurityContextHolder.getContext();
@GetMapping(value = "/getLicenses")
public ResponseEntity<List<License>> getLicenses() {
System.out.println("SecurityContext: " + securityContext);
System.out.println("Authentication securityContext: " + securityContext.getAuthentication());
return new ResponseEntity<List<License>>(licenseService.getLicenses(), null, HttpStatus.OK);
}
The output from console after access to /getLicenses is:
SecurityContext: org.springframework.security.core.context.SecurityContextImpl@ffffffff: Null authentication
Authentication securityContext: null
My KeycloakSecurityConfig.class
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity( prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class KeycloakSecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
auth.authenticationProvider(keycloakAuthenticationProvider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.csrf().disable();
http.authorizeRequests()
.antMatchers("/getLicenses").hasAnyRole("GUEST", "ADMIN", "SUPERADMIN")
.antMatchers("/getRevision/{id}").hasRole("SUPERADMIN")
.permitAll();
}
@Bean
@Override
protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
}
It works fine, if I try to access to /getRevision/{id} end-point with a 'GUEST' role user, it can't permit it.
My .yml has a BD connection, JPA and keycloak connection:
keycloak.auth-server-url : XXXX
keycloak.realm: XXXX
keycloak.resource: login
keycloak.public-client: true
And Keycloak has 3 users with 3 different roles (1 rol each user). I can do login with Postman
Does anyone know why I get null when trying to access SecurityContext
?
My goal is to retrieve user data
You are initializing the securityContext object in your controller when the controller is first created:
private SecurityContext securityContext = SecurityContextHolder.getContext();
At that time, there is no security context available, meaning that the context is always null.
Don't use a private variable in a controller to store the context, instead, fetch it from the SecurityContextHolder
in the getLicenses
method:
@GetMapping(value = "/getLicenses")
public ResponseEntity<List<License>> getLicenses() {
SecurityContext securityContext = SecurityContextHolder.getContext();
System.out.println("SecurityContext: " + securityContext);
System.out.println("Authentication securityContext: " + securityContext.getAuthentication());
return new ResponseEntity<List<License>>(licenseService.getLicenses(), null, HttpStatus.OK);
}