diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java index 5f5cba160e..31cb13aa60 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerJwkConfiguration.java @@ -35,6 +35,7 @@ import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2Res import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; import org.springframework.security.config.web.server.ServerHttpSecurity; import org.springframework.security.config.web.server.ServerHttpSecurity.OAuth2ResourceServerSpec; import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator; @@ -49,6 +50,7 @@ import org.springframework.security.oauth2.jwt.NimbusReactiveJwtDecoder.JwkSetUr import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; import org.springframework.security.oauth2.jwt.SupplierReactiveJwtDecoder; import org.springframework.security.web.server.SecurityWebFilterChain; +import org.springframework.security.web.server.WebFilterChainProxy; import org.springframework.util.CollectionUtils; /** @@ -177,6 +179,13 @@ class ReactiveOAuth2ResourceServerJwkConfiguration { server.jwt((jwt) -> jwt.jwtDecoder(decoder)); } + @Configuration(proxyBeanMethods = false) + @ConditionalOnMissingBean(WebFilterChainProxy.class) + @EnableWebFluxSecurity + static class EnableWebFluxSecurityConfiguration { + + } + } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerOpaqueTokenConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerOpaqueTokenConfiguration.java index f4d9614253..dbeb778d87 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerOpaqueTokenConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerOpaqueTokenConfiguration.java @@ -22,10 +22,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; import org.springframework.security.config.web.server.ServerHttpSecurity; import org.springframework.security.oauth2.server.resource.introspection.ReactiveOpaqueTokenIntrospector; import org.springframework.security.oauth2.server.resource.introspection.SpringReactiveOpaqueTokenIntrospector; import org.springframework.security.web.server.SecurityWebFilterChain; +import org.springframework.security.web.server.WebFilterChainProxy; import static org.springframework.security.config.Customizer.withDefaults; @@ -64,6 +66,13 @@ class ReactiveOAuth2ResourceServerOpaqueTokenConfiguration { return http.build(); } + @Configuration(proxyBeanMethods = false) + @ConditionalOnMissingBean(WebFilterChainProxy.class) + @EnableWebFluxSecurity + static class EnableWebFluxSecurityConfiguration { + + } + } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfiguration.java index f995f66cdd..b4d4394bfe 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,13 +20,18 @@ import reactor.core.publisher.Flux; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.security.SecurityProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; +import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.core.userdetails.ReactiveUserDetailsService; import org.springframework.security.web.server.WebFilterChainProxy; import org.springframework.web.reactive.config.WebFluxConfigurer; @@ -49,9 +54,28 @@ public class ReactiveSecurityAutoConfiguration { @Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(WebFilterChainProxy.class) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) + @Conditional(ReactiveAuthenticationManagerCondition.class) @EnableWebFluxSecurity static class EnableWebFluxSecurityConfiguration { } + static final class ReactiveAuthenticationManagerCondition extends AnyNestedCondition { + + ReactiveAuthenticationManagerCondition() { + super(ConfigurationPhase.REGISTER_BEAN); + } + + @ConditionalOnBean(AuthenticationManager.class) + static final class ConditionalOnAuthenticationManagerBean { + + } + + @ConditionalOnBean(ReactiveUserDetailsService.class) + static final class ConditionalOnReactiveUserDetailsService { + + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveUserDetailsServiceAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveUserDetailsServiceAutoConfiguration.java index c2f4ce2a73..1c27555263 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveUserDetailsServiceAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveUserDetailsServiceAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2022 the original author or authors. + * Copyright 2012-2023 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -55,7 +55,7 @@ import org.springframework.util.StringUtils; * @author Madhura Bhave * @since 2.0.0 */ -@AutoConfiguration(after = RSocketMessagingAutoConfiguration.class) +@AutoConfiguration(before = ReactiveSecurityAutoConfiguration.class, after = RSocketMessagingAutoConfiguration.class) @ConditionalOnClass({ ReactiveAuthenticationManager.class }) @ConditionalOnMissingBean( value = { ReactiveAuthenticationManager.class, ReactiveUserDetailsService.class, diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java index e8165ee189..9583efcbc4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/oauth2/resource/reactive/ReactiveOAuth2ResourceServerAutoConfigurationTests.java @@ -740,7 +740,6 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests { .isEqualTo("aud"); } - @EnableWebFluxSecurity static class TestConfig { @Bean @@ -782,6 +781,7 @@ class ReactiveOAuth2ResourceServerAutoConfigurationTests { } + @EnableWebFluxSecurity @Configuration(proxyBeanMethods = false) static class SecurityWebFilterChainConfig { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfigurationTests.java index 4436ab7360..54bdfb739a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/reactive/ReactiveSecurityAutoConfigurationTests.java @@ -20,6 +20,7 @@ import org.junit.jupiter.api.Test; import reactor.core.publisher.Flux; import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration.EnableWebFluxSecurityConfiguration; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; import org.springframework.context.annotation.Bean; @@ -47,6 +48,13 @@ class ReactiveSecurityAutoConfigurationTests { .run((context) -> assertThat(context).hasSingleBean(WebFilterChainProxy.class)); } + @Test + void backsOffWhenReactiveAuthenticationManagerNotPresent() { + this.contextRunner.withConfiguration(AutoConfigurations.of(ReactiveSecurityAutoConfiguration.class)) + .run((context) -> assertThat(context).hasSingleBean(ReactiveSecurityAutoConfiguration.class) + .doesNotHaveBean(EnableWebFluxSecurityConfiguration.class)); + } + @Test void enablesWebFluxSecurity() { this.contextRunner