I am trying to add a filter chain into my spring boot application like below.
@Bean
public SecurityFilterChain filterChain(HttpSecurity http, MyTokenIntrospector myTokenIntrospector) throws Exception {
return http
.httpBasic(AbstractHttpConfigurer::disable)
.formLogin(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(
authorizeHttpRequests -> authorizeHttpRequests
.requestMatchers("/actuator/health").permitAll()
.dispatcherTypeMatchers(DispatcherType.ERROR).permitAll()
.requestMatchers(HttpMethod.OPTIONS).permitAll() //for csrf OPTIONS queries
.anyRequest().authenticated()
)
.csrf(AbstractHttpConfigurer::disable)
.addFilterAfter(new MyAuthExtractorFilter(), BearerTokenAuthenticationFilter.class)
.oauth2ResourceServer(oauth2 -> oauth2
.bearerTokenResolver(new MyBasicTokenResolver())
.opaqueToken(opaqueToken -> opaqueToken.introspector(myTokenIntrospector))
.authenticationEntryPoint(new BasicAuthenticationEntryPoint())
)
.sessionManagement(sessionManager -> sessionManager.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.build();
}
I noticed that spring boot was invoking a different filter chain than the one that I defined above. I could always put @Order(1)
on the bean, but I would like to know why there is another filter chain defined.
When I put a breakpoint in org.springframework.security.WebSecurityConfiguration
in the block below, I can see that there are 2
filter chains defined in this.securityFilterChains
. One of them is the one that I defined, and the other one seems to be some kind of default.
Is there a way to tell spring to just use my filter chain that I defined? Or do I need to apply Order(1)
to use mine?
public Filter springSecurityFilterChain() throws Exception {
boolean hasFilterChain = !this.securityFilterChains.isEmpty();
if (!hasFilterChain) {
this.webSecurity.addSecurityFilterChainBuilder(() -> {
this.httpSecurity.authorizeHttpRequests((authorize) -> {
((AuthorizeHttpRequestsConfigurer.AuthorizedUrl)authorize.anyRequest()).authenticated();
});
this.httpSecurity.formLogin(Customizer.withDefaults());
this.httpSecurity.httpBasic(Customizer.withDefaults());
return (SecurityFilterChain)this.httpSecurity.build();
});
}
For some context, I am building a spring boot security library for use in all of my spring applications. Here is the full security configuration class that I am using.
@Configuration
@ComponentScan(basePackages = {"org.app.security"}, excludeFilters = {@ComponentScan.Filter(Configuration.class)})
@EnableWebSecurity
public class MySecurityConfiguration {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http, MtServerTokenIntrospector mtserverTokenIntrospector) throws Exception {
return http
.httpBasic(AbstractHttpConfigurer::disable)
.formLogin(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(
authorizeHttpRequests -> authorizeHttpRequests
.requestMatchers("/actuator/health").permitAll()
.dispatcherTypeMatchers(DispatcherType.ERROR).permitAll()
.requestMatchers(HttpMethod.OPTIONS).permitAll() //for csrf OPTIONS queries
.anyRequest().authenticated()
)
.csrf(AbstractHttpConfigurer::disable)
.addFilterAfter(new MyAuthExtractorFilter(), BearerTokenAuthenticationFilter.class)
.oauth2ResourceServer(oauth2 -> oauth2
.bearerTokenResolver(new MyBasicTokenResolver())
.opaqueToken(opaqueToken -> opaqueToken.introspector(mtserverTokenIntrospector))
.authenticationEntryPoint(new BasicAuthenticationEntryPoint())
)
.sessionManagement(sessionManager -> sessionManager.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.build();
}
}
I am also using this auto-configuration that I've setup.
@Configuration
@AutoConfigureBefore(SecurityAutoConfiguration.class)
@AutoConfigureAfter(MyHttpClientAutoConfiguration.class)
@ConditionalOnProperty(prefix = "app.security", name = "enabled", havingValue = "true", matchIfMissing = true)
@ComponentScan(basePackages = "org.app.security.config")
public class MySecurityAutoConfiguration {
}
I figured out that by using OAuth2 Resource Server, we are invoking oauth2 auto configuration through OAuth2ResourceServerAutoConfiguration.class
. As a result, it will create a default filter chain if one isn't detected.
Instead of executing before the SecurityAutoConfiguration class, I decided to execute before the OAuth2ResourceServerAutoConfiguration
class instead, and it works like a charm. I am only getting a single security filter chain.