0

I am migrating a project from spring boot 2.8 to spring boot 3. We used the code below to configure AuthentiationManagerBuilder in previous version. We cannot use configure method anymore because WebSecurityConfigurerAdapter has been removed in spring security 6.

  @SuppressWarnings("deprecation")
  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    if (!this.dmeAppSettings.isDevMode()) { // production
      auth.authenticationEventPublisher(authEventPub)
          .userDetailsService(userDetailsService())
          .passwordEncoder(pwdEncoder);
    } else {
      log.info("Configured to use in memory user accounts for authentication");
      auth.authenticationEventPublisher(authEventPub)
          .userDetailsService(userDetailsService())
          .and()
          .inMemoryAuthentication()
          .passwordEncoder(
              org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance())
          .withUser("user")
          .password("password")
          .roles("USER")
          .and()
          .passwordEncoder(
              org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance())
          .withUser("admin")
          .password("password")
          .roles(ADMIN_ONLY_ROLES)
          .and()
          .passwordEncoder(
              org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance())
          .withUser("sysadmin")
          .password("password")
          .roles(SYS_ADMIN_ROLES)
          .and()
          .passwordEncoder(
              org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance())
          .withUser("fsadmin")
          .password("password")
          .roles(FS_ADMIN_ROLES)
          .and()
          .passwordEncoder(
              org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance())
          .withUser("centcomadmin")
          .password("password")
          .roles(CENTCOM_ADMIN_ROLES);
    }
  }

  @Bean
  public UserDetailsService userDetailsService() {
    if (this.dmeAppSettings.isDevMode()) { // Dev mode.
      return new UserDetailsService() {
        @Override
        public UserDetails loadUserByUsername(String userId) throws UsernameNotFoundException {
          List<GrantedAuthority> auths = new ArrayList<>();
          if (userId.equalsIgnoreCase("ADMIN")) {
            for (String admin : ADMIN_ONLY_ROLES) {
              auths.add(new SimpleGrantedAuthority("ROLE_" + admin));
            }
          } else if (userId.equalsIgnoreCase("SYSADMIN")) {
            for (String admin : SYS_ADMIN_ROLES) {
              auths.add(new SimpleGrantedAuthority("ROLE_" + admin));
            }
          } else if (userId.equalsIgnoreCase("FSSADMIN")) {
            for (String admin : FS_ADMIN_ROLES) {
              auths.add(new SimpleGrantedAuthority("ROLE_" + admin));
            }
          } else if (userId.equalsIgnoreCase("CENTCOMADMIN")) {
            for (String admin : CENTCOM_ADMIN_ROLES) {
              auths.add(new SimpleGrantedAuthority("ROLE_" + admin));
            }
          }
          User result = new User(userId, "password", true, true, true, true, auths);
          return result;
        }
      };
    } else { // Production mode.
      return new DmeappUserService(dmeAppSettings, userServiceDb);
    }
  }

Basically, I want to configure the following settings via AuthenticationManagerBuilder:

  • Set custom authentication event publisher.
  • Use in memory authentication in dev mode.
  • Use database service in production mode.

I created AuthenticationManager Bean but got an exception. Is this the right way to configure AuthenticationManager?

  @Bean
  public AuthenticationManager authenticationManager(
      AuthenticationManagerBuilder auth)
      throws Exception {
    if (!this.dmeAppSettings.isDevMode()) { // production
      auth.authenticationEventPublisher(authEventPub)
          .userDetailsService(userDetailsService())
          .passwordEncoder(pwdEncoder);
    } else {
      log.info("Configured to use in memory user accounts for authentication");
      auth.authenticationEventPublisher(authEventPub)
          .userDetailsService(userDetailsService())
          .and()
          .inMemoryAuthentication()
          .passwordEncoder(
              org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance())
          .withUser("user").password("password").roles("USER")
          .and()
          .withUser("admin").password("password").roles(ADMIN_ONLY_ROLES)
          .and()
          .withUser("sysadmin").password("password").roles(SYS_ADMIN_ROLES)
          .and()
          .withUser("fsadmin").password("password").roles(FS_ADMIN_ROLES)
          .and()
          .withUser("centcomadmin").password("password").roles(CENTCOM_ADMIN_ROLES);
    }
    return auth.build();
  }

Exception stack trace:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'authenticationManager' defined in class path resource [com/missionessential/dmeapp/config/DmeappSecurityConfig.class]: Failed to instantiate [org.springframework.security.authentication.AuthenticationManager]: Factory method 'authenticationManager' threw exception with message: Cannot apply org.springframework.security.config.annotation.authentication.configurers.userdetails.DaoAuthenticationConfigurer@520a8ea1 to already built object
        at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:652)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:640)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1324)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1161)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:561)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:521)
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:961)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:915)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:584)
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:730)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:432)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1302)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1291)
        at com.missionessential.dmeapp.DmeappApplication.main(DmeappApplication.java:63)
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.security.authentication.AuthenticationManager]: Factory method 'authenticationManager' threw exception with message: Cannot apply org.springframework.security.config.annotation.authentication.configurers.userdetails.DaoAuthenticationConfigurer@520a8ea1 to already built object
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:171)
        at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:648)
        ... 19 common frames omitted
Caused by: java.lang.IllegalStateException: Cannot apply org.springframework.security.config.annotation.authentication.configurers.userdetails.DaoAuthenticationConfigurer@520a8ea1 to already built object
        at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.add(AbstractConfiguredSecurityBuilder.java:182)
        at org.springframework.security.config.annotation.AbstractConfiguredSecurityBuilder.apply(AbstractConfiguredSecurityBuilder.java:125)
        at org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder.apply(AuthenticationManagerBuilder.java:280)
        at org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder.userDetailsService(AuthenticationManagerBuilder.java:182)
        at org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration$DefaultPasswordEncoderAuthenticationManagerBuilder.userDetailsService(AuthenticationConfiguration.java:298)
        at com.missionessential.dmeapp.config.DmeappSecurityConfig.authenticationManager(DmeappSecurityConfig.java:230)
        at com.missionessential.dmeapp.config.DmeappSecurityConfig$$SpringCGLIB$$0.CGLIB$authenticationManager$0(<generated>)
        at com.missionessential.dmeapp.config.DmeappSecurityConfig$$SpringCGLIB$$2.invoke(<generated>)
        at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:257)
        at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331)
        at com.missionessential.dmeapp.config.DmeappSecurityConfig$$SpringCGLIB$$0.authenticationManager(<generated>)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:139)
        ... 20 common frames omitted

Ken
  • 1

0 Answers0