I need to use Keycloak and prefer to use stateless JWT tokens with my Spring Boot application. I can get it to run OK with sessions, but when converting this I need help
- Forcing Spring Boot Security to check for logins
- Allow a /logout URL (that goes to Keycloak)
My code "runs", but when I hit the initial page, I'm seeing log messages that seem to suggest it did not detect any sign of being logged in. When this happens, I'd like to force Spring Boot to redirect to the login page just like it would have had this been a stateful application.
org.springframework.web.servlet.FrameworkServlet: Failed to complete request: java.lang.NullPointerException: Cannot invoke "org.springframework.security.authentication.AbstractAuthenticationToken.getName()" because "authenticationToken" is null
org.springframework.security.web.context.HttpSessionSecurityContextRepository$SaveToSessionResponseWrapper: Did not store anonymous SecurityContext
org.springframework.security.web.context.SecurityContextPersistenceFilter: Cleared SecurityContextHolder to complete request
org.apache.juli.logging.DirectJDKLog: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.NullPointerException: Cannot invoke "org.springframework.security.authentication.AbstractAuthenticationToken.getName()" because "authenticationToken" is null] with root cause
java.lang.NullPointerException: Cannot invoke "org.springframework.security.authentication.AbstractAuthenticationToken.getName()" because "authenticationToken" is null
Here's my HttpSecurity snippet:
@Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.csrf()
// .disable().exceptionHandling().accessDeniedPage("/access-denied")
.and()
.authorizeRequests()
.antMatchers("/sso/**").permitAll()
.antMatchers("/error/**").permitAll()
.antMatchers("/css/**","/contact-us","/actuator/**","/isalive/**").permitAll()
.anyRequest().authenticated()
.and()
.oauth2Login()
.defaultSuccessUrl("/myfirstpage",true)
.and().exceptionHandling().authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
.and()
.oauth2ResourceServer().jwt();
}
I know I'm missing something, but I thought Keycloak provided a lot of these things OOTB. The initial URL is /. I had hoped the .authenticated() would force it to authenticate against all patterns not permitted, but I'm likely wrong. What am I missing?
Please note, the internet is awash with examples of Spring Boot Keycloak (a few are even good). It also has a lot of Spring Boot OAuth Stateless JWT. It does not have (that I can tell) a lot of Spring Boot Keycloak Stateless JWT. I got the little that I could find from this JHipster repo, but I feel like I'm missing some grand magical step.
CodePudding user response:
Resource-server should return 401 (unauthorized) when authentication is missing or invalid (expired, wrong issuer, etc.) and client should handle redirection to authorization-server.
Things get messy when you try to merge different OAuth2 actors (client, resource-server and authorization-server) into a single application.
Are you sure you want a Spring client (and not an Angular / React / Vue / Flutter / whatever client-side rendering framework)?
If yes, maybe should you start by splitting client (presenting login, logout and Thymeleaf or whatever pages) and resource-server (REST API) apps. You'll better understand spring-security conf you write (and can assert it works as expected individually).
Resource-server configuration (REST API)
Be aware that Keycloak adapters for spring are deprecated.
Easiest solution is here (support multi-tenancy, stateless by default, CORS configuration from properties, easy Keycloak roles mapping to Spring authorities and more).
You can also work directly with spring-boot-starter-oauth2-resource-server
, but it requires more java conf.
Client configuration (pages including login & logout)
- if keeping Spring, refer to spring-boot documentation: it's clear and always up to date (as opposed to most tutorials)
- if using a "modern" client-side framework, find a lib from certified list
I have a complete sample (Ionic-Angular UI with spring RESTful API) there, but it might be a little complicated as starter.
CodePudding user response:
You will need spring-security and keycloak-adapters This guid has full explanation how to setup and secure it