From 524a32879fea9179e9ba51c2c3a4ce031cdf8a13 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 1 Dec 2015 17:30:12 +0000 Subject: [PATCH] Allow security filter's dispatcher types to be configured via env This commit adds a new property, security.filter-dispatcher-types that can be used to configure the dispatcher types of Spring Security's filter chain. The default remains unchanged. Closes gh-4505 --- .../SecurityFilterAutoConfiguration.java | 1 + .../security/SecurityProperties.java | 18 ++++++- .../SecurityAutoConfigurationTests.java | 48 +++++++++++++++++++ .../appendix-application-properties.adoc | 1 + 4 files changed, 67 insertions(+), 1 deletion(-) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityFilterAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityFilterAutoConfiguration.java index 11a3ff42a15..3657cad59ba 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityFilterAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityFilterAutoConfiguration.java @@ -54,6 +54,7 @@ public class SecurityFilterAutoConfiguration { DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean( DEFAULT_FILTER_NAME); registration.setOrder(securityProperties.getFilterOrder()); + registration.setDispatcherTypes(securityProperties.getFilterDispatcherTypes()); return registration; } diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityProperties.java index 30998a4c302..e5b93570771 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/SecurityProperties.java @@ -18,9 +18,12 @@ package org.springframework.boot.autoconfigure.security; import java.util.ArrayList; import java.util.Arrays; +import java.util.EnumSet; import java.util.List; import java.util.UUID; +import javax.servlet.DispatcherType; + import org.springframework.boot.context.embedded.FilterRegistrationBean; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.core.Ordered; @@ -33,7 +36,7 @@ import org.springframework.util.StringUtils; * @author Dave Syer * @author Andy Wilkinson */ -@ConfigurationProperties(prefix = "security") +@ConfigurationProperties(prefix = "security", ignoreUnknownFields = false) public class SecurityProperties implements SecurityPrerequisite { /** @@ -98,6 +101,11 @@ public class SecurityProperties implements SecurityPrerequisite { */ private int filterOrder = DEFAULT_FILTER_ORDER; + /** + * Security filter chain dispatcher types. + */ + private EnumSet filterDispatcherTypes; + public Headers getHeaders() { return this.headers; } @@ -154,6 +162,14 @@ public class SecurityProperties implements SecurityPrerequisite { this.filterOrder = filterOrder; } + public EnumSet getFilterDispatcherTypes() { + return this.filterDispatcherTypes; + } + + public void setFilterDispatcherTypes(EnumSet filterDispatcherTypes) { + this.filterDispatcherTypes = filterDispatcherTypes; + } + public static class Headers { public enum HSTS { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/SecurityAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/SecurityAutoConfigurationTests.java index d1eead39cd7..38d62ef7d06 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/SecurityAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/SecurityAutoConfigurationTests.java @@ -16,6 +16,10 @@ package org.springframework.boot.autoconfigure.security; +import java.util.EnumSet; + +import javax.servlet.DispatcherType; + import org.junit.After; import org.junit.Test; @@ -54,11 +58,15 @@ import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension; import org.springframework.security.web.FilterChainProxy; +import org.springframework.test.util.ReflectionTestUtils; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -67,6 +75,7 @@ import static org.junit.Assert.fail; * * @author Dave Syer * @author Rob Winch + * @author Andy Wilkinson */ public class SecurityAutoConfigurationTests { @@ -360,6 +369,45 @@ public class SecurityAutoConfigurationTests { assertNotNull(this.context.getBean(SecurityEvaluationContextExtension.class)); } + @Test + public void defaultFilterDispatcherTypes() { + this.context = new AnnotationConfigWebApplicationContext(); + this.context.setServletContext(new MockServletContext()); + this.context.register(SecurityAutoConfiguration.class, + SecurityFilterAutoConfiguration.class, + ServerPropertiesAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); + this.context.refresh(); + DelegatingFilterProxyRegistrationBean bean = this.context.getBean( + "securityFilterChainRegistration", + DelegatingFilterProxyRegistrationBean.class); + @SuppressWarnings("unchecked") + EnumSet dispatcherTypes = (EnumSet) ReflectionTestUtils + .getField(bean, "dispatcherTypes"); + assertThat(dispatcherTypes, is(nullValue())); + } + + @Test + public void customFilterDispatcherTypes() { + this.context = new AnnotationConfigWebApplicationContext(); + this.context.setServletContext(new MockServletContext()); + this.context.register(SecurityAutoConfiguration.class, + SecurityFilterAutoConfiguration.class, + ServerPropertiesAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class); + EnvironmentTestUtils.addEnvironment(this.context, + "security.filter-dispatcher-types:INCLUDE,ERROR"); + this.context.refresh(); + DelegatingFilterProxyRegistrationBean bean = this.context.getBean( + "securityFilterChainRegistration", + DelegatingFilterProxyRegistrationBean.class); + @SuppressWarnings("unchecked") + EnumSet dispatcherTypes = (EnumSet) ReflectionTestUtils + .getField(bean, "dispatcherTypes"); + assertThat(dispatcherTypes, + is(EnumSet.of(DispatcherType.INCLUDE, DispatcherType.ERROR))); + } + private static final class AuthenticationListener implements ApplicationListener { diff --git a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 88de48b232b..f4ac785aa79 100644 --- a/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -390,6 +390,7 @@ content into your application; rather pick only the properties that you need. security.basic.realm=Spring # HTTP basic realm name. security.enable-csrf=false # Enable Cross Site Request Forgery support. security.filter-order=0 # Security filter chain order. + security.filter-dispatcher-types=ASYNC, FORWARD, INCLUDE, REQUEST # Security filter chain dispatcher types. security.headers.cache=true # Enable cache control HTTP headers. security.headers.content-type=true # Enable "X-Content-Type-Options" header. security.headers.frame=true # Enable "X-Frame-Options" header.