After migration to spring boot 3.2.1 (from 3.1.2) I'm facing the following issue:

    Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate 
    [org.springframework.security.web.server.SecurityWebFilterChain]: Factory method 'springSecurityFilterChain' threw 
    exception with message: authenticationManager cannot be null
            at 
    org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:177) ~ 
   [spring-beans-6.1.2.jar:6.1.2]
            at org.springframework.beans.factory.support.ConstructorResolver.instantiate(ConstructorResolver.java:651) ~ 
   [spring-beans-6.1.2.jar:6.1.2]
            ... 143 common frames omitted
    Caused by: java.lang.IllegalArgumentException: authenticationManager cannot be null
            at org.springframework.util.Assert.notNull(Assert.java:172) ~[spring-core-6.1.2.jar:6.1.2]
            at org.springframework.security.web.server.authentication.AuthenticationWebFilter.<init> 
   (AuthenticationWebFilter.java:94) ~[spring-security-web-6.2.1.jar:6.2.1]
            at 
    org.springframework.security.config.web.server.ServerHttpSecurity$HttpBasicSpec.configure(ServerHttpSecurity.java:2305) 
    ~[spring-security-config-6.2.1.jar:6.2.1]
            at org.springframework.security.config.web.server.ServerHttpSecurity.build(ServerHttpSecurity.java:1545) ~[spring- 
   security-config-6.2.1.jar:6.2.1]
            at 
org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration.sprin gSecurityFilterChain(ReactiveManagementWebSecurityAutoConfiguration.java:69) ~[spring-boot-actuator-autoconfigure- 3.2.1.jar:3.2.1]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
    at 
    org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:140) ~ 
    [spring-beans-6.1.2.jar:6.1.2]
    ... 144 common frames omitted

Relevant dependencies:

       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-validation</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>${jwt.version}</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>${jwt.version}</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-gson</artifactId>
            <version>${jwt.version}</version>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign.form</groupId>
            <artifactId>feign-form</artifactId>
            <version>${feign-form.version}</version>
        </dependency>
        <dependency>
            <groupId>com.github.ben-manes.caffeine</groupId>
            <artifactId>caffeine</artifactId>
            <version>${caffeine.version}</version>
        </dependency>
        <dependency>
            <groupId>com.playtika.reactivefeign</groupId>
            <artifactId>feign-reactor-spring-cloud-starter</artifactId>
            <version>${reactive-feign.version}</version>
            <type>pom</type>
        </dependency>

Configuration file:

@Configuration
@ComponentScan(basePackageClasses = SecurityConfig.class)
@EnableReactiveMethodSecurity
@EnableWebFluxSecurity
@EnableConfigurationProperties({ ClientProperties.class, MultipleIssuersProperties.class })
class SecurityConfig {

    AuthenticationExceptionEntryPoint authenticationEntryPoint; // autowired
    Issuer mainIssuer;
    MultipleIssuersProperties issuers;
    List<String> whitelistedUrls;
    List<String> allowedOrigins;

   // Constructor omitted

    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
        return http
                .authorizeExchange(exchange -> exchange
                    .pathMatchers(whitelistedUrls.toArray(String[]::new))
                    .permitAll()
                    .anyExchange().authenticated())
                .cors(cors -> cors.configurationSource(corsConfigurationSource()))
                .csrf(CsrfSpec::disable)
                .exceptionHandling(exception -> exception.authenticationEntryPoint(authenticationEntryPoint))
                .oauth2ResourceServer(server -> server.authenticationManagerResolver(reactiveAuthenticationManagerResolver()))
                .build();
    }

    @Bean
    public JwtIssuerReactiveAuthenticationManagerResolver reactiveAuthenticationManagerResolver() {
        var managers = new HashMap<String, ReactiveAuthenticationManager>();
        managers.put(
            mainIssuer.issuerUri(),
            new JwtReactiveAuthenticationManager(reactiveJwtDecoder())
        );

        issuers.issuers().forEach(issuer -> {
            var jwkSource = reactiveRemoteJWKSource(issuer);
            var jwtDecoder = reactiveJwtDecoder(issuer, jwkSource);
            var manager = new JwtReactiveAuthenticationManager(jwtDecoder);
            managers.put(issuer.issuerUri(), manager);

        });
        return new JwtIssuerReactiveAuthenticationManagerResolver(issuer -> justOrEmpty(managers.get(issuer)));
    }

    @Bean
    public ReactiveJwtDecoder reactiveJwtDecoder() {
        return reactiveJwtDecoder(mainIssuer, reactiveRemoteJWKSource());
    }

    // other beans omitted

Codebase remains unchanged, aside from version upgrade.

Comment From: wilkinsona

After migration to spring boot 3.2.1

What version were you using previously?

Relevant dependencies I think there may be other dependencies that are relevant. For example, I can see ReactiveManagementWebSecurityAutoConfiguration which is part of Spring Boot's actuator but is not shown in your dependencies.

If you would like us to spend some more time investigating, please spend some time providing a complete yet minimal sample that reproduces the problem. You can share it with us by pushing it to a separate repository on GitHub or by zipping it up and attaching it to this issue.

Comment From: razvdana

Edited*, will try to find some time tomorrow to set up something

Comment From: razvdana

Update: Somehow I missed some conditionals so the entire SecurityConfig is not loaded. Then through auto configuration it leads to

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'httpHandler' defined in class path resource [org/springframework/boot/autoconfigure/web/reactive/HttpHandlerAutoConfiguration$AnnotationConfig.class]: Failed to instantiate [org.springframework.http.server.reactive.HttpHandler]: Factory method 'httpHandler' threw exception with message: Error creating bean with name 'org.springframework.security.config.annotation.web.reactive.WebFluxSecurityConfiguration': Unsatisfied dependency expressed through method 'setSecurityWebFilterChains' parameter 0: Error creating bean with name 'springSecurityFilterChain' defined in class path resource [org/springframework/boot/actuate/autoconfigure/security/reactive/ReactiveManagementWebSecurityAutoConfiguration.class]: Failed to instantiate [org.springframework.security.web.server.SecurityWebFilterChain]: Factory method 'springSecurityFilterChain' threw exception with message: authenticationManager cannot be null

What would be the recommended approach to conditionally disable security ? Define a web filter chain with permitAll, or disable some auto configurations ?

Comment From: wilkinsona

It's hard to say. In your case, ReactiveManagementWebSecurityAutoConfiguration caused the problem. That's the auto-configuration for Actuator security in a WebFlux app. It could be that it should have backed off automatically. You could exclude it, but that may mask an underlying problem rather than solving it. I think we'll really need a sample that reproduces the problem to be able to offer any specific advice or identify if a fix needs to be made.

Comment From: razvdana

Created this demo project.

Comment From: wilkinsona

Thank you.

It works in 3.1.x due to the auto-configuration of a MapReactiveUserDetailsService by ReactiveUserDetailsServiceAutoConfiguration. From this user details service, Spring Security is able to create the authentication manager that the basic auth configured in ReactiveManagementWebSecurityAutoConfiguration requires.

It does not work in 3.2.x due to https://github.com/spring-projects/spring-boot/issues/35338 which means that the MapReactiveUserDetailsService is no longer auto-configured as you have resource server on the classpath. The same problem occurs with 3.1.x if ReactiveUserDetailsServiceAutoConfiguration is excluded. This is another variant of https://github.com/spring-projects/spring-boot/issues/37504 that we'd overlooked previously and is the same as the problems that we attempted to fix in https://github.com/spring-projects/spring-boot/commit/afad358047c4fa9a0a9281d406e875279528a495.

This fix made in https://github.com/spring-projects/spring-boot/commit/afad358047c4fa9a0a9281d406e875279528a495 doesn't work here due to the auto-configuration ordering. The deny-all authentication manager is auto-configured by ReactiveSecurityAutoConfiguration in the absence of a ReactiveAuthenticationManager, a ReactiveUserDetailsService, and a SecurityWebFilterChain:

https://github.com/spring-projects/spring-boot/blob/d032b9d2342d23036d66223ee2297c431896828d/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfiguration.java#L59-L64

ReactiveManagementWebSecurityAutoConfiguration is ordered before ReactiveSecurityAutoConfiguration and defines a SecurityWebFilterChain, causing the auto-configuration of the deny-all authentication manager to back off.

For the purposes of Actuator security, I think we need to auto-configure a deny-all authentication manager when there's no ReactiveAuthenticationManager and no ReactiveUserDetailsService. I'm not yet sure how the ordering will work out though.

Comment From: wilkinsona

Closed by https://github.com/spring-projects/spring-boot/commit/6ec56da91910fb76a5e10a0b48809de1712f181e.