Reputation: 4070
I implemented a customFilter that adds something from the request`s cookies to its headers :
@Component
@Slf4j
public class MyCustomFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
.... some logic...
log.info("Sending request to next chain for validation..");
chain.doFilter(request, response);
log.info("Authentication completed sucessfully");
}
@Bean
// This method is needed to replace the default cookieFilter.json processor of tomcat that ignores the jwt cookieFilter.json
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> cookieProcessorCustomizer() {
return tomcatServletWebServerFactory -> tomcatServletWebServerFactory.addContextCustomizers((TomcatContextCustomizer) context -> {
context.setCookieProcessor(new LegacyCookieProcessor());
});
}
}
My WebSecurityConfigurerAdapter class :
@Configuration
public class AuthSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//configuring strategy
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.anyRequest().authenticated().and()
.oauth2ResourceServer().jwt().and();
http.csrf().disable();
http.addFilterBefore(new MyCustomFilter (), UsernamePasswordAuthenticationFilter.class);
http.exceptionHandling().authenticationEntryPoint(new AuthExceptionEntryPoint());
}
}
When I run the code and send a request via postman/curl I see that the filter triggered twice in the
Sending request to next chain for validation..
Sending request to next chain for validation..
Authentication completed sucessfully
Authentication completed sucessfully
I found a few posts about issue and I tried the following solutions :
It happens because spring registers the beans automatically and I add the filter manually in the configure method. Therefore, I removed the manually addition of the filter in the configure() method. The result was that the filter wasnt called at all.
Instead of implementing the filter interface, try to extend the OncePerRequestFilter
class. Done that, but the filter still triggered twice.
Tried also to remove the @Component
annotation and add the filter manually. In addition I had to move the CookieProcessor
bean to the Configuration class. The problem that raised afterwards is that the app fails to start because of the following error :
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.web.servlet.HandlerMapping]: Factory method 'resourceHandlerMapping' threw exception; nested exception is java.lang.IllegalStateException: No ServletContext set
I am using spring-security version 5.3.3.
Upvotes: 1
Views: 2520
Reputation: 124601
As a rule of thumb, don't add @Bean
methods to @Component
classes as those are handled differently than those in @Configuration
classes. (See this).
The your code in the @Bean
is too complex. Create and return a TomcatContextCustomizer
to do the modification. Your code will lead to circulair references which will lead to initializing errors.
Add the following @Bean
method to your @SpringBootApplication
annotated class
@Bean
public TomactContextCustomizer cookieProcessorCustomizer() {
return (context) -> context.setCookieProcessor(new LegacyCookieProcessor());
}
Now in your Filter
either remove the @Component
or add an accompying FilterRegistrationBean
to prevent it from being added to the regular chain of filters. (Spring Boot automatically registers all detected Filter
instances to the regular filter chain).
@Bean
public FilterRegistrationBean<MyFilter> myFilterRegistrationBean(MyFilter myFilter) {
FilterRegistrationBean<MyFilter> frb = new FilterRegistrationBean<>(myFilter);
frb.setEnabled(false);
return frb;
}
If you remove @Component
the above snippet isn't needed if you don't then you should reuse the scanned MyFilter
instance in your security configuration.
@Configuration
public class AuthSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private MyFilter myFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
//configuring strategy
http.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.anyRequest().authenticated().and()
.oauth2ResourceServer().jwt().and();
http.csrf().disable();
http.addFilterBefore(myFilter, UsernamePasswordAuthenticationFilter.class);
http.exceptionHandling().authenticationEntryPoint(new AuthExceptionEntryPoint());
}
}
Upvotes: 3