Spring-boot: Make it easier to order a filter after Spring Security's filter

Created on 30 Sep 2014  路  14Comments  路  Source: spring-projects/spring-boot

I am trying to add my custom filter after Spring Security but I am unable to set order of filters. None of examples below work. My filter is alway added to the beginning of the chain.

@Bean
@Order(Ordered.LOWEST_PRECEDENCE)
public UserInsertingMdcFilter userInsertingMdcFilter() {
    return new UserInsertingMdcFilter();
}

This didn't work too:

@Bean
public FilterRegistrationBean userInsertingMdcFilterRegistrationBean() {
    FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    UserInsertingMdcFilter userFilter = new UserInsertingMdcFilter();
    registrationBean.setFilter(userFilter);
    registrationBean.setOrder(Integer.MAX_VALUE);
    return registrationBean;
}
enhancement

Most helpful comment

Spring Security doesn't set an order on the Filter bean that it creates. This means that, when Boot is creating a FilterRegistrationBean for it, it gets the default order which is LOWEST_PRECEDENCE.

If you want your own Filter to go after Spring Security's you can create your own registration for Spring Security's filter and specify the order. For example:

    @Bean
    public FilterRegistrationBean securityFilterChain(
            @Qualifier(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) Filter securityFilter) {
        FilterRegistrationBean registration = new FilterRegistrationBean(securityFilter);
        registration.setOrder(0);
        registration
                .setName(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
        return registration;
    }

@rwinch Does it make sense to change Spring Security to set an order on the springSecurityFilterChain bean created in WebSecurityConfiguration so that it's something higher than LOWEST_PRECEDENCE by default?

All 14 comments

Spring Security doesn't set an order on the Filter bean that it creates. This means that, when Boot is creating a FilterRegistrationBean for it, it gets the default order which is LOWEST_PRECEDENCE.

If you want your own Filter to go after Spring Security's you can create your own registration for Spring Security's filter and specify the order. For example:

    @Bean
    public FilterRegistrationBean securityFilterChain(
            @Qualifier(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) Filter securityFilter) {
        FilterRegistrationBean registration = new FilterRegistrationBean(securityFilter);
        registration.setOrder(0);
        registration
                .setName(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
        return registration;
    }

@rwinch Does it make sense to change Spring Security to set an order on the springSecurityFilterChain bean created in WebSecurityConfiguration so that it's something higher than LOWEST_PRECEDENCE by default?

Since ordering is so important, I'm a little hesitant to do this as it can impact the security of an application. Please feel free to create a JIRA for consideration.

Thanks, Rob. I've opened SEC-2730.

Hmm, I'm now bouncing against this issue as well.
Isn't it strange that the Spring Security filter is registered with LOWEST_PRECEDENCE by default?
I would have expected highest precedence to be honest..

Can we at least make is easier to change the order in Boot? Maybe a application property?
Most people want to avoid the coding the FilterRegistrationBean for the securityFilterChain(..).

I too was surprised that it was LOWEST_PRECEDENCE as I'd expected that you'd want the security filter to run as early as possible. I'll defer to @rwinch on that though.

If changing the precedence is that right thing to do, then I'd rather the change was made in Spring Security. If Rob tells us it's not the right thing to do then I'm not sure that we want to make it easy for people to do it. In short, let's wait and see what @rwinch says.

OK I agree. In all cases I've seen the security filter would always have been the first filter. Before request logging filter, mdc filter etc.
Anyway let's see what @rwinch says.

Spring Security is not always the first Filter. A few examples that come to mind are:

  • OpenEntityManagerInViewFilter must be first when using JPA in Spring Security code,
  • CharacterEncodingFilter should typically be before Spring Security
  • Spring Session's SessionRepositoryFilter must be before Spring Security in order to ensure the HttpSession is overridden before Spring Security is invoked
  • Various logging and exception handling Filters are often best placed before Spring Security
  • MultipartFilter must be first when handling multipart file uploads with CSRF protection

So a few things we must consider...

What are the order values of these other Filter's? Do we have a "well known" specification for them?

I wonder why setting an order on Filter matters for Spring Security in general. It seems that Order only matters in Boot applications. Can we think of other reasons that Order being specified provides value?

If the only reason is for Boot applications, then it seems we are running into a slippery slope. Why not have Spring's ApplicationInitializer's automatically add the Filter's at that point? Note I don't agree with dong this, but am pointing out that if order only makes sense in the context of boot, then we likely need to figure out a way to keep that logic there.

OK, so I think there should be an easy way to set the security filter somewhere in the middle.
Above suggestion is to set the order to 0 but now I wonder what the default Order is for e.g. OpenEntityManagerInViewFilter, CharacterEncodingFilter etc.
I think many Boot users won't understand how to set this up correctly.

NOTE: If Spring Security was specifying an order at all, then I would agree that it is something that needs to change in Spring Security. However, Spring Security does not set any Order on the springSecurityFilterChain (Why would it other than a Boot context?) which semantically is quite a bit different than specifying it as Ordered.LOWEST_PRECEDENCE. In the Boot context, it sorts the Filters using AnnotationAwareOrderComparator which treats anything that does not have an @Order annotation and does not implement Ordered as Ordered.LOWEST_PRECEDENCE. So that is why I asked "Can we think of other reasons that Order being specified provides value?" Without an answer to this, I think it may not make sense for Spring Security to do this. In that case, it may make sense to have Boot use OrderSourceProvider and metadata to determine the sorted order.

Thanks, Rob. It's certainly Boot that's responsible for finding Filter beans in the application context and auto-registering them with the servlet container. That, plus the points you've made above, goes quite a long way to convincing me that it should be Boot that fixes this. The other filters that you've mentioned aren't, as far as I'm aware, automatically configured so it's up to the user to specify an order when they configure them.

@wilkinsona What do you suggest to do then? Based on feedback from @rwinch there are many filters that should be before the security filter, on the other (as we both expected) there are also many cases where we expect filters after the security filter.
Wouldn't it be better that Boot auto configuration configures it somewhere in the middle? Like order 0 as in the code you posted. Probably use a constant so we can refer to the value from other registrations. At least this gives a easy solution to configure our own filters before and after the security filter and we don't have to tamper with the order of the security filter in each project. Like I said many won't fully understand how to do this.

@marceloverdijk What you've described is pretty much exactly what I think we should do

Thx!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

philwebb picture philwebb  路  45Comments

philwebb picture philwebb  路  42Comments

dsyer picture dsyer  路  32Comments

masc3d picture masc3d  路  33Comments

philwebb picture philwebb  路  33Comments