Describe the bug
Spring Security automatically adds a default SecurityFilterChain
when no SecurityFilterChain
bean has been configured. This conflicts with SecurityFilterChain
s added via a WebSecurityCustomizer
resulting in an UnreachableFilterChainException
at application startup because the automatically configured filter chain matches any request.
To Reproduce
@Configuration(proxyBeanMethods = false)
public class SecurityConfiguration {
@Bean
public WebSecurityCustomizer security(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(registry -> registry.anyRequest().permitAll());
var chain = http.build();
return web -> web.addSecurityFilterChainBuilder(() -> chain);
}
}
Expected behavior
The default SecurityFilterChain
should only be added to the WebSecurity
if no SecurityBuilder<? extends SecurityFilterChain>
is present after adding all SecurityFilterChain
beans and applying all WebSecurityCustomizer
s.
Comment From: SeungyoupBaek
Hi, I’d like to work on this issue.
I can reproduce the problem and plan to update the logic so the default SecurityFilterChain
is only added when no other chains are present.
Could you assign this to me? Thanks!
Comment From: jzheaux
Thanks, @jbb01. Can you say more about what you are trying to achieve? I'm hesitate to change logic like this if a more idiomatic way exists. From what I can tell, you are able to do the following:
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeHttpRequests(registry -> registry.anyRequest().permitAll());
return http.build();
}
This will override the default and be registered with WebSecurity
. Why do you need the other approach?
Comment From: jbb01
Thanks for the feedback.
I'm trying to dynamically create zero or more SecurityFilterChain
s based on external configuration. The only ways I know how to achieve this are
- using a WebSecurityCustomizer
as described above or
- using a BeanDefinitionRegistryPostProcessor
to dynamically register the filter chains as beans. This however limits what external configuration can be considered as the post processor is executed early in the lifecycle.
- always registering all possible filter chains as beans but replacing the ones not needed with empty filter chains that don't match any request. This approach falls short if, based on config, no custom filter chains are registered as the empty chains prevent registration of the default.
Of those three, using a WebSecurityCustomizer
seemed like the cleanest approach. If you know of a better solution, please enlighten me.
As far as I can see, moving the check for already registered filter chains to after the customizers are applied, should be a relatively non-invasive change, as the WebSecurity
has no API for querying already registered filter chain builders. Therefore a web security customizer couldn't possibly depend on the default filter chain already being registered when it gets executed.