Merge branch '1.5.x'
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user