Skip to content

Commit 0cdb1d3

Browse files
committed
Make Spring Security's filter's order configurable and default to zero
Previously, Spring Security's filter had no configured order. Due to the use of AnnotationAwareOrderComparater this meant that its order defaulted to LOWEST_PRECEDENCE. This meant that a user had to declare a FilterRegistrationBean for the filter and explicitly set its order if they want another filter to run after Spring Security's. This commit updates the security auto-configuration to assign a default order of zero to Spring Security's filter, allowing filters to be easily configured to run before it or after it. This default value can overridden using the server.filter-order property. The default order is also exposed as a constant on SecurityProperties, allowing it to be referenced from other filter declarations. Closes spring-projectsgh-1640
1 parent cf24af0 commit 0cdb1d3

File tree

4 files changed

+63
-0
lines changed

4 files changed

+63
-0
lines changed

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityProperties.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ public class SecurityProperties implements SecurityPrequisite {
5555
*/
5656
public static final int IGNORED_ORDER = Ordered.HIGHEST_PRECEDENCE;
5757

58+
/**
59+
* The default order of Spring Security's Filter
60+
*/
61+
public static final int DEFAULT_FILTER_ORDER = 0;
62+
5863
private boolean requireSsl;
5964

6065
// Flip this when session creation is disabled by default
@@ -70,6 +75,8 @@ public class SecurityProperties implements SecurityPrequisite {
7075

7176
private final User user = new User();
7277

78+
private int filterOrder = DEFAULT_FILTER_ORDER;
79+
7380
public Headers getHeaders() {
7481
return this.headers;
7582
}
@@ -118,6 +125,14 @@ public List<String> getIgnored() {
118125
return this.ignored;
119126
}
120127

128+
public int getFilterOrder() {
129+
return this.filterOrder;
130+
}
131+
132+
public void setFilterOrder(int filterOrder) {
133+
this.filterOrder = filterOrder;
134+
}
135+
121136
public static class Headers {
122137

123138
public static enum HSTS {

spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SpringBootWebSecurityConfiguration.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,13 @@
2020
import java.util.Arrays;
2121
import java.util.List;
2222

23+
import javax.servlet.Filter;
2324
import javax.servlet.http.HttpServletRequest;
2425

2526
import org.springframework.beans.factory.annotation.Autowired;
27+
import org.springframework.beans.factory.annotation.Qualifier;
2628
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
29+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
2730
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
2831
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2932
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
@@ -32,6 +35,7 @@
3235
import org.springframework.boot.autoconfigure.security.SecurityProperties.Headers;
3336
import org.springframework.boot.autoconfigure.web.ErrorController;
3437
import org.springframework.boot.autoconfigure.web.ServerProperties;
38+
import org.springframework.boot.context.embedded.FilterRegistrationBean;
3539
import org.springframework.boot.context.properties.EnableConfigurationProperties;
3640
import org.springframework.context.annotation.Bean;
3741
import org.springframework.context.annotation.Configuration;
@@ -48,6 +52,7 @@
4852
import org.springframework.security.config.annotation.web.servlet.configuration.EnableWebMvcSecurity;
4953
import org.springframework.security.web.AuthenticationEntryPoint;
5054
import org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint;
55+
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
5156
import org.springframework.security.web.header.writers.HstsHeaderWriter;
5257
import org.springframework.security.web.util.matcher.AnyRequestMatcher;
5358
import org.springframework.security.web.util.matcher.RequestMatcher;
@@ -96,6 +101,18 @@ public WebSecurityConfigurer<WebSecurity> ignoredPathsWebSecurityConfigurerAdapt
96101
return new IgnoredPathsWebSecurityConfigurerAdapter();
97102
}
98103

104+
@Bean
105+
@ConditionalOnBean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
106+
public FilterRegistrationBean securityFilterChainRegistration(
107+
@Qualifier(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) Filter securityFilter,
108+
SecurityProperties securityProperties) {
109+
FilterRegistrationBean registration = new FilterRegistrationBean(securityFilter);
110+
registration.setOrder(securityProperties.getFilterOrder());
111+
registration
112+
.setName(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
113+
return registration;
114+
}
115+
99116
public static void configureHeaders(HeadersConfigurer<?> configurer,
100117
SecurityProperties.Headers headers) throws Exception {
101118
if (headers.getHsts() != Headers.HSTS.NONE) {

spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/SecurityAutoConfigurationTests.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
2828
import org.springframework.boot.autoconfigure.orm.jpa.test.City;
2929
import org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration;
30+
import org.springframework.boot.context.embedded.FilterRegistrationBean;
3031
import org.springframework.boot.test.EnvironmentTestUtils;
3132
import org.springframework.context.ApplicationEvent;
3233
import org.springframework.context.ApplicationListener;
@@ -82,6 +83,35 @@ public void testWebConfiguration() throws Exception {
8283
assertEquals(5, filterChains.size());
8384
}
8485

86+
@Test
87+
public void testDefaultFilterOrder() throws Exception {
88+
this.context = new AnnotationConfigWebApplicationContext();
89+
this.context.setServletContext(new MockServletContext());
90+
this.context.register(SecurityAutoConfiguration.class,
91+
ServerPropertiesAutoConfiguration.class,
92+
PropertyPlaceholderAutoConfiguration.class);
93+
this.context.refresh();
94+
assertEquals(
95+
0,
96+
this.context.getBean("securityFilterChainRegistration",
97+
FilterRegistrationBean.class).getOrder());
98+
}
99+
100+
@Test
101+
public void testCustomFilterOrder() throws Exception {
102+
this.context = new AnnotationConfigWebApplicationContext();
103+
EnvironmentTestUtils.addEnvironment(this.context, "security.filter-order:12345");
104+
this.context.setServletContext(new MockServletContext());
105+
this.context.register(SecurityAutoConfiguration.class,
106+
ServerPropertiesAutoConfiguration.class,
107+
PropertyPlaceholderAutoConfiguration.class);
108+
this.context.refresh();
109+
assertEquals(
110+
12345,
111+
this.context.getBean("securityFilterChainRegistration",
112+
FilterRegistrationBean.class).getOrder());
113+
}
114+
85115
@Test
86116
public void testDisableIgnoredStaticApplicationPaths() throws Exception {
87117
this.context = new AnnotationConfigWebApplicationContext();

spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ content into your application; rather pick only the properties that you need.
168168
security.basic.enabled=true
169169
security.basic.realm=Spring
170170
security.basic.path= # /**
171+
security.filter-order=0
171172
security.headers.xss=false
172173
security.headers.cache=false
173174
security.headers.frame=false

0 commit comments

Comments
 (0)