9

I have a custom filter which is called before BasicAuthenticationFilter, the Bean is autowired in the SecurityConfig file.

.addFilterBefore(preAuthTenantContextInitializerFilter, BasicAuthenticationFilter.class)

Here is how the filter looks like.

@Component
public class PreAuthTenantContextInitializerFilter extends OncePerRequestFilter {
    @Autowired
    private TenantService tenantService;
.....
.....

I want this filter to not fire just like the rest of the Spring Security filter chain for paths included in WebSecurityConfigurerAdapter#configure(WebSecurity web) web.ignoring().

Here is how it looks like

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/v2/api-docs", "/configuration/ui", "/swagger-resources", 
                                    "/configuration/security", "/swagger-ui.html", 
                                    "/webjars/**","/swagger-resources/configuration/ui",
                                    "/swagge‌​r-ui.html", "/docs/**");
    }
}

What I have already tried.

Remove the @Component annotation from the filter class, it only prevented the filter from invoking in any case since the filter is no more picked as a bean and will never make it to the filter chain.

What I am looking for

I want this filter to be called when the rest of the Spring Security chain is called and be ignored for the paths in web.ignoring() just like the rest of the Spring Security filters. Thanks.

Adil Khalil
  • 2,073
  • 3
  • 21
  • 33
  • 4
    Because it is a bean Spring Boot detects is and adds it to the regular filter chain. Due to the extension of the `OncePerRequestFilter` it will only execute once, basically the entry configured in your security filter chain does nothing. To fix don't make it a bean and wire the dependencies yourself. That way Spring Boot won't detect it and it will be only part of the Spring Security filter chain instead of the regular filter chain. Or add a `FilterRegistrationBean` for the filter and set `enabled` to `false` to prevent it from being automatically registered. – M. Deinum Oct 06 '17 at 05:53
  • Possible duplicate of [Spring webSecurity.ignoring() doesn't ignore custom filter](https://stackoverflow.com/questions/39152803/spring-websecurity-ignoring-doesnt-ignore-custom-filter) – rougou Apr 30 '18 at 06:49

2 Answers2

19

Any Servlet, Filter or Servlet *Listener instance that is a Spring bean will be registered with the embedded container. This can be particularly convenient if you want to refer to a value from your application.properties during configuration.

This snippet comes from the Spring Boot reference guide. Basically any Filter detected in the application context will be registered to the default filter chain and mapped to the DispatcherServlet or / .

In your case, as the filter is marked as @Component it will be a bean, Spring Boot detects is and registers it with the embedded container. However you don't want that as you want it to, only, be part of the Spring Security filter chain.

To do so you have 2 options.

  1. Remove the @Component and @Autowired and construct your own instance and don't make it a bean.
  2. Add an additional [FilterRegistrationBean] and set the enabled property to false, this will prevent Spring Boot from registering it with the embedded container.

Herer is the solution for option 2:

@Bean
public FilterRegistrationBean preAuthTenantContextInitializerFilterRegistration(PreAuthTenantContextInitializerFilter filter) {
    FilterRegistrationBean registration = new FilterRegistrationBean(filter);
    registration.setEnabled(false);
    return registration;
}

With this added bean Spring Boot will not register the filter with the embedded container and as such it will only be invoked as part of your Spring Security filter chain.

M. Deinum
  • 115,695
  • 22
  • 220
  • 224
  • 1
    Thank you. This was the crucial part that i missed. So by annotating filter as @Component, it gets automatically registered in underlying container filter chain and it also gets added to spring security filter chain (if u add it manually with addFilterBefore or addFilterAfter) So now that filter gets invoked twice. – SeaBiscuit Sep 04 '19 at 20:19
2
  • I presume you are trying to ignore security for loading the Swagger UI page. If that's the case you need to add another path, /swagger-resources/configuration/security, to your list of ignored paths. Once you add this path, your PreAuthTenantContextInitializerFilter will not be invoked when you call any of the ignored paths.
  • Also, manage the creation of the PreAuthTenantContextInitializerFilter manually instead of having Spring managed. It will involve removing @Component from your filter. You can find a working example here.

    @Configuration
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
       private TenantService service;
    
       @Autowired
       public SecurityConfiguration(TenantService service) {
           this.service = service;
       }
    
       @Override
       protected void configure(HttpSecurity http) throws Exception {
           http.addFilterBefore(
               new PreAuthTenantContextInitializerFilter(service),
               BasicAuthenticationFilter.class);
           ...
       }
    
       @Override
       public void configure(WebSecurity web) throws Exception {
           web.ignoring().antMatchers("/v2/api-docs", 
                "/configuration/ui",
                "/swagger-resources",
                "/configuration/security", "/swagger-ui.html",
                "/webjars/**", "/swagger-resources/configuration/ui",
                "/swagge‌r-ui.html", "/docs/**",
                "/swagger-resources/configuration/security");
       }
    }
    
Indra Basak
  • 7,124
  • 1
  • 26
  • 45