Improve conditions for enabling WebFlux security

This commit correct a mistake where AuthenticationManager was used
instead of ReactiveAuthenticationManager. It also expands the
conditions so that WebFlux security will be enabled when the user
has defined their own SecurityWebFilterChain. In such a situation
no other security-related beans may be needed to use WebFlux
security as things may have been configured directly using the DSL.

Closes gh-37504
This commit is contained in:
Andy Wilkinson 2023-09-30 09:04:04 +01:00
parent ff99de49c4
commit 4493958f13
2 changed files with 28 additions and 7 deletions

View File

@ -29,9 +29,10 @@ import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.core.userdetails.ReactiveUserDetailsService; import org.springframework.security.core.userdetails.ReactiveUserDetailsService;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.WebFilterChainProxy; import org.springframework.security.web.server.WebFilterChainProxy;
import org.springframework.web.reactive.config.WebFluxConfigurer; import org.springframework.web.reactive.config.WebFluxConfigurer;
@ -54,20 +55,20 @@ public class ReactiveSecurityAutoConfiguration {
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(WebFilterChainProxy.class) @ConditionalOnMissingBean(WebFilterChainProxy.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE) @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
@Conditional(ReactiveAuthenticationManagerCondition.class) @Conditional(EnableWebFluxSecurityCondition.class)
@EnableWebFluxSecurity @EnableWebFluxSecurity
static class EnableWebFluxSecurityConfiguration { static class EnableWebFluxSecurityConfiguration {
} }
static final class ReactiveAuthenticationManagerCondition extends AnyNestedCondition { static final class EnableWebFluxSecurityCondition extends AnyNestedCondition {
ReactiveAuthenticationManagerCondition() { EnableWebFluxSecurityCondition() {
super(ConfigurationPhase.REGISTER_BEAN); super(ConfigurationPhase.REGISTER_BEAN);
} }
@ConditionalOnBean(AuthenticationManager.class) @ConditionalOnBean(ReactiveAuthenticationManager.class)
static final class ConditionalOnAuthenticationManagerBean { static final class ConditionalOnReactiveAuthenticationManagerBean {
} }
@ -76,6 +77,11 @@ public class ReactiveSecurityAutoConfiguration {
} }
@ConditionalOnBean(SecurityWebFilterChain.class)
static final class ConditionalOnSecurityWebFilterChain {
}
} }
} }

View File

@ -25,9 +25,11 @@ import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.core.userdetails.MapReactiveUserDetailsService; import org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.WebFilterChainProxy; import org.springframework.security.web.server.WebFilterChainProxy;
import org.springframework.web.reactive.config.WebFluxConfigurer; import org.springframework.web.reactive.config.WebFluxConfigurer;
@ -57,11 +59,24 @@ class ReactiveSecurityAutoConfigurationTests {
} }
@Test @Test
void enablesWebFluxSecurity() { void enablesWebFluxSecurityWhenUserDetailsServiceIsPresent() {
this.contextRunner.withUserConfiguration(UserDetailsServiceConfiguration.class) this.contextRunner.withUserConfiguration(UserDetailsServiceConfiguration.class)
.run((context) -> assertThat(context).getBean(WebFilterChainProxy.class).isNotNull()); .run((context) -> assertThat(context).getBean(WebFilterChainProxy.class).isNotNull());
} }
@Test
void enablesWebFluxSecurityWhenReactiveAuthenticationManagerIsPresent() {
this.contextRunner
.withBean(ReactiveAuthenticationManager.class, () -> mock(ReactiveAuthenticationManager.class))
.run((context) -> assertThat(context).getBean(WebFilterChainProxy.class).isNotNull());
}
@Test
void enablesWebFluxSecurityWhenSecurityWebFilterChainIsPresent() {
this.contextRunner.withBean(SecurityWebFilterChain.class, () -> mock(SecurityWebFilterChain.class))
.run((context) -> assertThat(context).getBean(WebFilterChainProxy.class).isNotNull());
}
@Test @Test
void autoConfigurationIsConditionalOnClass() { void autoConfigurationIsConditionalOnClass() {
this.contextRunner this.contextRunner