Adds support for Content Security Policy

Fixes gh-2342
This commit is contained in:
Joe Grandja
2016-03-17 10:07:40 -04:00
committed by Rob Winch
parent 4cb9b202f8
commit 2f7f2ff589
9 changed files with 675 additions and 17 deletions

View File

@@ -15,6 +15,7 @@
*/
package org.springframework.security.config.annotation.web.configurers
import org.springframework.beans.factory.BeanCreationException
import org.springframework.security.config.annotation.BaseSpringSpec
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
@@ -24,6 +25,7 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
*
* @author Rob Winch
* @author Tim Ysewyn
* @author Joe Grandja
*/
class HeadersConfigurerTests extends BaseSpringSpec {
@@ -387,4 +389,68 @@ class HeadersConfigurerTests extends BaseSpringSpec {
.reportUri("http://example.net/pkp-report")
}
}
def "headers.contentSecurityPolicy default header"() {
setup:
loadConfig(ContentSecurityPolicyDefaultConfig)
request.secure = true
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['Content-Security-Policy': 'default-src \'self\'']
}
@EnableWebSecurity
static class ContentSecurityPolicyDefaultConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.contentSecurityPolicy("default-src 'self'");
}
}
def "headers.contentSecurityPolicy report-only header"() {
setup:
loadConfig(ContentSecurityPolicyReportOnlyConfig)
request.secure = true
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['Content-Security-Policy-Report-Only': 'default-src \'self\'; script-src trustedscripts.example.com']
}
@EnableWebSecurity
static class ContentSecurityPolicyReportOnlyConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.contentSecurityPolicy("default-src 'self'; script-src trustedscripts.example.com").reportOnly();
}
}
def "headers.contentSecurityPolicy empty policyDirectives"() {
when:
loadConfig(ContentSecurityPolicyInvalidConfig)
then:
thrown(BeanCreationException)
}
@EnableWebSecurity
static class ContentSecurityPolicyInvalidConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.contentSecurityPolicy("");
}
}
}

View File

@@ -830,6 +830,84 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
expected.message.contains 'policy'
}
def 'http headers defaults : content-security-policy'() {
setup:
httpAutoConfig {
'headers'() {
'content-security-policy'('policy-directives':'default-src \'self\'')
}
}
createAppContext()
when:
def hf = getFilter(HeaderWriterFilter)
MockHttpServletResponse response = new MockHttpServletResponse()
hf.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
def expectedHeaders = [:] << defaultHeaders
expectedHeaders['Content-Security-Policy'] = 'default-src \'self\''
then:
assertHeaders(response, expectedHeaders)
}
def 'http headers disabled : content-security-policy not included'() {
setup:
httpAutoConfig {
'headers'(disabled:true) {
'content-security-policy'('policy-directives':'default-src \'self\'')
}
}
createAppContext()
when:
def hf = getFilter(HeaderWriterFilter)
then:
!hf
}
def 'http headers defaults disabled : content-security-policy only'() {
setup:
httpAutoConfig {
'headers'('defaults-disabled':true) {
'content-security-policy'('policy-directives':'default-src \'self\'')
}
}
createAppContext()
when:
def hf = getFilter(HeaderWriterFilter)
MockHttpServletResponse response = new MockHttpServletResponse()
hf.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
then:
assertHeaders(response, ['Content-Security-Policy':'default-src \'self\''])
}
def 'http headers defaults : content-security-policy with empty directives'() {
when:
httpAutoConfig {
'headers'() {
'content-security-policy'('policy-directives':'')
}
}
createAppContext()
then:
thrown(BeanDefinitionParsingException)
}
def 'http headers defaults : content-security-policy report-only=true'() {
setup:
httpAutoConfig {
'headers'() {
'content-security-policy'('policy-directives':'default-src https:; report-uri https://example.com/', 'report-only':true)
}
}
createAppContext()
when:
def hf = getFilter(HeaderWriterFilter)
MockHttpServletResponse response = new MockHttpServletResponse()
hf.doFilter(new MockHttpServletRequest(secure:true), response, new MockFilterChain())
def expectedHeaders = [:] << defaultHeaders
expectedHeaders['Content-Security-Policy-Report-Only'] = 'default-src https:; report-uri https://example.com/'
then:
assertHeaders(response, expectedHeaders)
}
def assertHeaders(MockHttpServletResponse response, Map<String,String> expected) {
assert response.headerNames == expected.keySet()
expected.each { headerName, value ->