7

I'm using Spring-Security 3.2.4 and Spring Boot 1.1.0 (and it's related dependencies versions 4.X). I'm writing a web application that will be run in an embedded tomcat.

I'm trying to add two additional filters(not related to Spring security) that one of them will be invoked before the Spring-Security-FilterChainProxy and the other one will be invoked after the Spring-Security-FilterChainProxy.

My Spring-Security configuration files:

@Configuration
@EnableWebMvcSecurity
public class SecurityCtxConfig extends WebSecurityConfigurerAdapter {

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth
    .inMemoryAuthentication()
        .withUser("user").password("pass").roles("USER");
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf()
            .disable()
            .authorizeRequests()
            .anyRequest()
            .authenticated()
            .and()
            .formLogin()
            .usernameParameter("user").passwordParameter("password");
}
}

And the Main class (Application.class):

@Configuration
@ComponentScan
@EnableAutoConfiguration
public class Application {

    @Bean
RequestFilter beforeSpringSecurityFilter(){
    return new RequestFilter();
}

@Bean
RequestFilter afterSpringSecurityFilter(){
    return new RequestFilter();
}

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

And the Filter implementation:

public class RequestFilter extends OncePerRequestFilter {

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
        FilterChain filterChain) throws ServletException, IOException {
        filterChain.doFilter(request, response);
}

}

Is there a way to controll the invocation order when taking in account the FilterChainProxy (that is beeing created by the WebSecurityConfigurerAdapter ? To be percise, the required order is:

  1. request-filter-1
  2. Spring-Security FilterChain
  3. request-filter-2

Thanks

Modi
  • 2,200
  • 4
  • 23
  • 37

4 Answers4

11

Agree with everything stated by Dave Syer ;) but wished to add a Java Config example of using the FilterRegistrationBean.

In my situation, I was finding that my custom security filter (using Spring Security) was being fired twice for every request. Adding the FilterRegistrationBean config fixed this.

    @Bean(name = "myFilter")
    public MyAuthenticationFilter myAuthenticationFilter(final MyAuthenticationEntryPoint entryPoint) {
        final MyAuthenticationFilter filter = new MyAuthenticationFilter();
        filter.setEntryPoint(entryPoint);
        return filter;
    }

    /**
     *  We do this to ensure our Filter is only loaded once into Application Context
     *
     */
    @Bean(name = "authenticationFilterRegistration")
    public FilterRegistrationBean myAuthenticationFilterRegistration(final MyAuthenticationFilter filter) {
        final FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(filter);
        filterRegistrationBean.setEnabled(false);
        return filterRegistrationBean;
    }

(Regarding my specific issue of filter being registered twice in Application Context - Rather than using a FilterRegistrationBean, I also found re-implementing the MyAuthenticationFilter to inherit from OncePerRequestFilter instead of GenericFilterBean also worked. However, OncePerRequestFilter support is from Servlet 3.x upwards and since I was writing a public library, support from Servlet 2.x may be needed)

arcseldon
  • 35,523
  • 17
  • 121
  • 125
6

The FilterChainProxy use by Spring Security is not Ordered (if it was you could order all your filters). But you should be able to register it in a FilterRegistrationBean which is Ordered and register your other filters the same way. In the case of the security filter you can inject it by name into the registration bean. The others you can probably inject by calling a @Bean method.

Dave Syer
  • 56,583
  • 10
  • 155
  • 143
  • Thank you so much @Dave Syer. What I'm still missing is why isn't there two filter chains now, I mean how is the framework is a ware to the fact that I added a FilterRegistration Bean (that wraps the filter chain) so that the filter chain it self wont be added as a filter, I'll be more than happy I you can elaborate a bit. – Modi Jun 24 '14 at 08:30
  • Look at the code in `EmbeddedWebApplicationContext` where it analyses the `FilterRegistrationBeans`. We don't double register the filters that are already part of a registration. – Dave Syer Jun 24 '14 at 13:20
1

At some point spring boot exposed the security filter as a property. This is now pretty easy to do.

In you application.yml:

  spring:
    security:
      filter:
        order: 20

And some filter you want to invoke after Spring Security does it's thing:

@Bean
public FilterRegistrationBean<Filter> afterAuthFilterRegistrationBean() {
    FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
    //a filter that extends OncePerRequestFilter
    AfterAuthFilter afterAuthFilter = new AfterAuthFilter();
    registrationBean.setFilter(afterAuthFilter);
    //this needs to be a number greater than than spring.security.filter.order
    registrationBean.setOrder(30);
    return registrationBean;
}

For a filter that is executed before Spring security, set the order to a number less than 20.

Jim Cox
  • 974
  • 7
  • 10
0

If you are using web.xml approaches, you can follow this: https://stackoverflow.com/a/11929129/1542363

If you using Java config approaches, you can do this in WebSecurityConfigurerAdapter

@Override
protected void configure(HttpSecurity http) throws Exception {

    http.addFilterBefore(your-request-filter-1, ChannelProcessingFilter.class);
    http.addFilterAfter(your-request-filter-2, SwitchUserFilter.class);

}

Always check the library version you are using, and refer to the specific document for the correct order of the filter chains:

https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#ns-custom-filters

Or, if you using AbstractSecurityWebApplicationInitializer, you can use the insertFilters or appendFilters.

public class SecurityApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

    @Override
    protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
        insertFilters(servletContext, new MultipartFilter());
    }
}

More info You can refer this: https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#csrf-multipart

Sam YC
  • 10,725
  • 19
  • 102
  • 158