Breaking change in 9.0.1/9.0.2?

I believe this breaking change happened in 9.0.1, but am unable to test that, given that I can’t find a repository with the 9.0.1 artifacts (see Keycloak 9.0.1 missing from Central). After upgrading, all my tests fail.

I have a config, as was required up through 9.0.0

import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
@Configuration
class KeycloakPropertiesConfig {
    @Bean
    fun keycloakConfigResolver() =
        KeycloakSpringBootConfigResolver()
}

I tried deleting the config, but that also failed saying it couldn’t find a needed bean.

I am using Spring Boot 2.2.6.RELEASE, which worked with
org.keycloak:keycloak-spring-boot-starter:9.0.0
org.keycloak:keycloak-admin-client:9.0.0
But fails with 9.0.2 or newer, with

java.lang.NullPointerException
at org.keycloak.adapters.KeycloakDeploymentBuilder.internalBuild(KeycloakDeploymentBuilder.java:57)
at org.keycloak.adapters.KeycloakDeploymentBuilder.build(KeycloakDeploymentBuilder.java:202)
at org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver.resolve(KeycloakSpringBootConfigResolver.java:39)
at org.keycloak.adapters.springsecurity.config.KeycloakSpringConfigResolverWrapper.resolve(KeycloakSpringConfigResolverWrapper.java:40)
at org.keycloak.adapters.AdapterDeploymentContext.resolveDeployment(AdapterDeploymentContext.java:89)
at org.keycloak.adapters.springsecurity.filter.KeycloakPreAuthActionsFilter.doFilter(KeycloakPreAuthActionsFilter.java:82)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.web.filter.CorsFilter.doFilterInternal(CorsFilter.java:92)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:109)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:134)
at org.springframework.test.web.servlet.MockMvc.perform(MockMvc.java:183)

Related links

  • https ://www.keycloak.org/docs/latest/release_notes/index.html#fixed-the-automatic-resolution-of-code-keycloakconfigresolver-code-instances-for-spring-boot-applications
  • https ://github.com/spring-projects/spring-boot/issues/6514
  • https ://github.com/spring-projects/spring-boot/commit/0384a88b57b70c2ad73f84447a87429ae0d83edf
  • https ://stackoverflow.com/questions/61228097/npe-when-loading-custom-securityconfig-for-keycloak-in-webmvctest (sorry they’re not clickable, I’m circumventing Discourse’s 2 link limit for new users).
  • https ://github.com/keycloak/keycloak-community/issues/102
  • https ://github.com/ch4mpy/spring-addons/issues/2
  • https ://issues.redhat.com/browse/KEYCLOAK-14020
  • https ://issues.redhat.com/browse/KEYCLOAK-14520
  • https ://github.com/keycloak/keycloak/pull/7189

It looks like this is tracked in https://issues.redhat.com/browse/KEYCLOAK-14520. The workaround mentioned there worked for me once I also deleted the KeycloakSpringBootConfigResolver bean that was required up through 9.0.0.