Unable to use Keycloak in Spring Boot 2.1 due to duplicated Bean Registration httpSessionManager

14,524

Solution 1

It looks like there's a bug in Keycloak's Spring Security integration which means that an application that subclasses KeycloakWebSecurityConfigurerAdapter will try to create two beans named httpSessionManager. When two beans are defined with the same name, the second definition that is encountered will attempt to override the first. This overriding is prohibited by default in Spring Boot 2.1. I would recommend reporting this as a bug against Keycloak's Spring Security integration. While you are waiting for the bug to be resolved, you can work around the problem by setting spring.main.allow-bean-definition-overriding=true in application.properties.

Solution 2

This helped me to resolve an issue, remove @KeycloakConfiguration and use this instead (from KEYCLOAK-8725):

Java:

@Configuration
@ComponentScan(
        basePackageClasses = KeycloakSecurityComponents.class,
        excludeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.keycloak.adapters.springsecurity.management.HttpSessionManager"))
@EnableWebSecurity

Kotlin:

@Configuration
@ComponentScan(
    basePackageClasses = [KeycloakSecurityComponents::class],
    excludeFilters = [ComponentScan.Filter(type = FilterType.REGEX, pattern = ["org.keycloak.adapters.springsecurity.management.HttpSessionManager"])]
)
@EnableWebSecurity

Solution 3

The preferred way to address the duplicate HttpSessionManager bean definition is to override the creation of this bean in your SecurityConfig and add a conditional annotation on the instantiation of it like the following:

@KeycloakConfiguration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Import(KeycloakWebSecurityConfigurerAdapter.class)
class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
    @Bean
    @Override
    @ConditionalOnMissingBean(HttpSessionManager.class)
    protected HttpSessionManager httpSessionManager() {
        return new HttpSessionManager();
    }
}

Solution 4

I use keycloak-spring-security-adapter in version 6.0.1.The solution to remove @KeycloakConfiguration with special configuration did not work for me.

My solution was to add the following line in application.properties:

spring.main.allow-bean-definition-overriding: true
Share:
14,524
Tobias Bertram-Köhler
Author by

Tobias Bertram-Köhler

Updated on June 06, 2022

Comments

  • Tobias Bertram-Köhler
    Tobias Bertram-Köhler almost 2 years

    I want to secure my Spring Boot 2.1 app with Keycloak 4.5.

    Currently I cannot start the application due to the following error:

    Exception encountered during context initialization - cancelling refresh attempt: 
    org.springframework.beans.factory.support.BeanDefinitionOverrideException: 
      Invalid bean definition with name 'httpSessionManager' defined in class path resource [dummy/service/SecurityConfig.class]: 
        Cannot register bean definition [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=securityConfig; factoryMethodName=httpSessionManager; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [dummy/SecurityConfig.class]] for bean 'httpSessionManager': 
    There is already [Generic bean: class [org.keycloak.adapters.springsecurity.management.HttpSessionManager]; scope=singleton; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in URL [jar:file:/.m2/repository/org/keycloak/keycloak-spring-security-adapter/4.5.0.Final/keycloak-spring-security-adapter-4.5.0.Final.jar!/org/keycloak/adapters/springsecurity/management/HttpSessionManager.class]] bound.
    

    My class SecurityConfig (see below) extends from KeycloakWebSecurityConfigurerAdapter. This adapter already defines the bean httpSessionManager.

    I understand why this is a problem. Question is, how can I prevent this or fix my conflict?

    The Steps I have done so far:

    • Built my pom (see below) using:
      • spring-boot-starter-web
      • spring-boot-starter-security
      • keycloak-spring-boot-starter
      • keycloak-adapter-bom in dependencyManagement
    • Defined an own SecurityConfig extending KeycloakWebSecurityConfigurerAdapter

    pom.xml

    ...
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.0.RELEASE</version>
    </parent>
    
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    
        <java.version>11</java.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
    
        <keycloak.version>4.5.0.Final</keycloak.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.keycloak</groupId>
            <artifactId>keycloak-spring-boot-starter</artifactId>
        </dependency>
    </dependencies>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.keycloak.bom</groupId>
                <artifactId>keycloak-adapter-bom</artifactId>
                <version>${keycloak.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    ...
    

    SecurityConfig.java

    @KeycloakConfiguration
    @EnableGlobalMethodSecurity(prePostEnabled = true)
    @Import(KeycloakWebSecurityConfigurerAdapter.class)
    class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {
    
        @Autowired
        public void configureGlobal(AuthenticationManagerBuilder auth) {
            KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();
            keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());
            auth.authenticationProvider(keycloakAuthenticationProvider);
        }
    
        @Bean
        @Override
        protected SessionAuthenticationStrategy sessionAuthenticationStrategy() {
            return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl());
        }
    
        @Bean
        public KeycloakConfigResolver keycloakConfigResolver() {
            return new KeycloakSpringBootConfigResolver();
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            super.configure(http);
            http.csrf().ignoringAntMatchers("/**/*");
            http.authorizeRequests()
                    .anyRequest().permitAll();
        }
    }
    

    Update There is a known issue (KEYCLOAK-8725). The fix is planned for 5.x of Keycloak. However, there was a workaround in the comments. Just replace the annotation @KeyCloakConfiguration with:

    @Configuration
    @ComponentScan(
        basePackageClasses = KeycloakSecurityComponents.class,
        excludeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = "org.keycloak.adapters.springsecurity.management.HttpSessionManager"))
    @EnableWebSecurity