Merge branch '1.5.x'

This commit is contained in:
Phillip Webb
2016-11-16 16:06:53 -08:00
22 changed files with 155 additions and 31 deletions

View File

@@ -30,7 +30,7 @@ import org.springframework.jdbc.support.SQLExceptionTranslator;
import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;
/**
* Transforms {@link java.sql.SQLException} into a Spring-specific @{link
* Transforms {@link java.sql.SQLException} into a Spring-specific {@link
* DataAccessException}.
*
* @author Lukas Eder

View File

@@ -174,6 +174,20 @@ public class SecurityProperties implements SecurityPrerequisite {
NONE, DOMAIN, ALL
}
public enum ContentSecurityPolicyMode {
/**
* Use the 'Content-Security-Policy' header.
*/
DEFAULT,
/**
* Use the 'Content-Security-Policy-Report-Only' header.
*/
REPORT_ONLY
}
/**
* Enable cross site scripting (XSS) protection.
*/
@@ -194,6 +208,16 @@ public class SecurityProperties implements SecurityPrerequisite {
*/
private boolean contentType = true;
/**
* Value for content security policy header.
*/
private String contentSecurityPolicy;
/**
* Security policy mode.
*/
private ContentSecurityPolicyMode contentSecurityPolicyMode = ContentSecurityPolicyMode.DEFAULT;
/**
* HTTP Strict Transport Security (HSTS) mode (none, domain, all).
*/
@@ -231,6 +255,23 @@ public class SecurityProperties implements SecurityPrerequisite {
this.contentType = contentType;
}
public String getContentSecurityPolicy() {
return this.contentSecurityPolicy;
}
public void setContentSecurityPolicy(String contentSecurityPolicy) {
this.contentSecurityPolicy = contentSecurityPolicy;
}
public ContentSecurityPolicyMode getContentSecurityPolicyMode() {
return this.contentSecurityPolicyMode;
}
public void setContentSecurityPolicyMode(
ContentSecurityPolicyMode contentSecurityPolicyMode) {
this.contentSecurityPolicyMode = contentSecurityPolicyMode;
}
public HSTS getHsts() {
return this.hsts;
}

View File

@@ -29,6 +29,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.security.SecurityProperties.Headers;
import org.springframework.boot.autoconfigure.security.SecurityProperties.Headers.ContentSecurityPolicyMode;
import org.springframework.boot.autoconfigure.web.ErrorController;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -108,6 +109,16 @@ public class SpringBootWebSecurityConfiguration {
if (!headers.isContentType()) {
configurer.contentTypeOptions().disable();
}
if (StringUtils.hasText(headers.getContentSecurityPolicy())) {
String policyDirectives = headers.getContentSecurityPolicy();
ContentSecurityPolicyMode mode = headers.getContentSecurityPolicyMode();
if (mode == ContentSecurityPolicyMode.DEFAULT) {
configurer.contentSecurityPolicy(policyDirectives);
}
else {
configurer.contentSecurityPolicy(policyDirectives).reportOnly();
}
}
if (!headers.isXss()) {
configurer.xssProtection().disable();
}

View File

@@ -16,6 +16,7 @@
package org.springframework.boot.autoconfigure.condition;
import org.junit.After;
import org.junit.Test;
import org.springframework.boot.cloud.CloudPlatform;
@@ -33,6 +34,13 @@ public class ConditionalOnCloudPlatformTests {
private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@After
public void cleanUp() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void outcomeWhenCloudfoundryPlatformNotPresentShouldNotMatch()
throws Exception {

View File

@@ -213,7 +213,9 @@ public class SpringBootWebSecurityConfigurationTests {
.andExpect(MockMvcResultMatchers.header().string("Cache-Control",
is(notNullValue())))
.andExpect(MockMvcResultMatchers.header().string("X-Frame-Options",
is(notNullValue())));
is(notNullValue())))
.andExpect(MockMvcResultMatchers.header()
.doesNotExist("Content-Security-Policy"));
}
@Test
@@ -239,6 +241,39 @@ public class SpringBootWebSecurityConfigurationTests {
MockMvcResultMatchers.header().doesNotExist("X-Frame-Options"));
}
@Test
public void contentSecurityPolicyConfiguration() throws Exception {
this.context = SpringApplication.run(VanillaWebConfiguration.class,
"--security.headers.content-security-policy=default-src 'self';");
MockMvc mockMvc = MockMvcBuilders
.webAppContextSetup((WebApplicationContext) this.context)
.addFilters((FilterChainProxy) this.context
.getBean("springSecurityFilterChain", Filter.class))
.build();
mockMvc.perform(MockMvcRequestBuilders.get("/"))
.andExpect(MockMvcResultMatchers.header()
.string("Content-Security-Policy", is("default-src 'self';")))
.andExpect(MockMvcResultMatchers.header()
.doesNotExist("Content-Security-Policy-Report-Only"));
}
@Test
public void contentSecurityPolicyReportOnlyConfiguration() throws Exception {
this.context = SpringApplication.run(VanillaWebConfiguration.class,
"--security.headers.content-security-policy=default-src 'self';",
"--security.headers.content-security-policy-mode=report-only");
MockMvc mockMvc = MockMvcBuilders
.webAppContextSetup((WebApplicationContext) this.context)
.addFilters((FilterChainProxy) this.context
.getBean("springSecurityFilterChain", Filter.class))
.build();
mockMvc.perform(MockMvcRequestBuilders.get("/"))
.andExpect(MockMvcResultMatchers.header().string(
"Content-Security-Policy-Report-Only", is("default-src 'self';")))
.andExpect(MockMvcResultMatchers.header()
.doesNotExist("Content-Security-Policy"));
}
@Configuration
@Import(TestWebConfiguration.class)
@Order(Ordered.LOWEST_PRECEDENCE)

View File

@@ -577,7 +577,7 @@ public class WebMvcAutoConfigurationTests {
}
@Test
public void welcomePageMappingDoesNotHandleRequestThatDoNotAcceptTextHtml()
public void welcomePageMappingDoesNotHandleRequestsThatDoNotAcceptTextHtml()
throws Exception {
load("spring.resources.static-locations:classpath:/welcome-page/");
assertThat(this.context.getBeansOfType(WelcomePageHandlerMapping.class))