Migrate HeadersConfigurerTests groovy->java

Issue: gh-4939
This commit is contained in:
Eleftheria Stein 2019-05-30 15:15:49 -04:00 committed by Josh Cummings
parent 7806ac21aa
commit 16b0d782f4
2 changed files with 659 additions and 568 deletions

View File

@ -1,568 +0,0 @@
/*
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
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
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import static org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter.ReferrerPolicy
/**
* Tests for {@link HeadersConfigurer}.
*
* @author Rob Winch
* @author Tim Ysewyn
* @author Joe Grandja
* @author Eddú Meléndez
* @author Vedran Pavic
*/
class HeadersConfigurerTests extends BaseSpringSpec {
def "headers"() {
setup:
loadConfig(HeadersConfig)
request.secure = true
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['X-Content-Type-Options':'nosniff',
'X-Frame-Options':'DENY',
'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
'Expires' : '0',
'Pragma':'no-cache',
'X-XSS-Protection' : '1; mode=block']
}
@EnableWebSecurity
static class HeadersConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.headers()
}
}
def "headers.contentType"() {
setup:
loadConfig(ContentTypeOptionsConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['X-Content-Type-Options':'nosniff']
}
@EnableWebSecurity
static class ContentTypeOptionsConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.contentTypeOptions()
}
}
def "headers.frameOptions"() {
setup:
loadConfig(FrameOptionsConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['X-Frame-Options':'DENY']
}
@EnableWebSecurity
static class FrameOptionsConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.frameOptions()
}
}
def "headers.hsts"() {
setup:
loadConfig(HstsConfig)
request.secure = true
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains']
}
@EnableWebSecurity
static class HstsConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.httpStrictTransportSecurity()
}
}
def "headers.cacheControl"() {
setup:
loadConfig(CacheControlConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
'Expires' : '0',
'Pragma':'no-cache']
}
@EnableWebSecurity
static class CacheControlConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.cacheControl()
}
}
def "headers.xssProtection"() {
setup:
loadConfig(XssProtectionConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['X-XSS-Protection' : '1; mode=block']
}
@EnableWebSecurity
static class XssProtectionConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.xssProtection()
}
}
def "headers custom x-frame-options"() {
setup:
loadConfig(HeadersCustomSameOriginConfig)
request.secure = true
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['X-Content-Type-Options':'nosniff',
'X-Frame-Options':'SAMEORIGIN',
'Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains',
'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
'Expires' : '0',
'Pragma':'no-cache',
'X-XSS-Protection' : '1; mode=block']
}
@EnableWebSecurity
static class HeadersCustomSameOriginConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.frameOptions().sameOrigin()
}
}
def "headers.hpkp no pins"() {
setup:
loadConfig(HpkpConfigNoPins)
request.secure = true
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == [:]
}
@EnableWebSecurity
static class HpkpConfigNoPins extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.httpPublicKeyPinning()
}
}
def "headers.hpkp"() {
setup:
loadConfig(HpkpConfig)
request.secure = true
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['Public-Key-Pins-Report-Only' : 'max-age=5184000 ; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="']
}
def "headers.hpkp no secure request"() {
setup:
loadConfig(HpkpConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == [:]
}
@EnableWebSecurity
static class HpkpConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.httpPublicKeyPinning()
.addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=")
}
}
def "headers.hpkp with pins"() {
setup:
loadConfig(HpkpConfigWithPins)
request.secure = true
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['Public-Key-Pins-Report-Only' : 'max-age=5184000 ; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=" ; pin-sha256="E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g="']
}
@EnableWebSecurity
static class HpkpConfigWithPins extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
Map<String, String> pins = new LinkedHashMap<>();
pins.put("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=", "sha256");
pins.put("E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=", "sha256");
http
.headers()
.defaultsDisabled()
.httpPublicKeyPinning()
.withPins(pins)
}
}
def "headers.hpkp custom age"() {
setup:
loadConfig(HpkpConfigCustomAge)
request.secure = true
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['Public-Key-Pins-Report-Only' : 'max-age=604800 ; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="']
}
@EnableWebSecurity
static class HpkpConfigCustomAge extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.httpPublicKeyPinning()
.addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=")
.maxAgeInSeconds(604800)
}
}
def "headers.hpkp terminate connection"() {
setup:
loadConfig(HpkpConfigTerminateConnection)
request.secure = true
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['Public-Key-Pins' : 'max-age=5184000 ; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM="']
}
@EnableWebSecurity
static class HpkpConfigTerminateConnection extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.httpPublicKeyPinning()
.addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=")
.reportOnly(false)
}
}
def "headers.hpkp include subdomains"() {
setup:
loadConfig(HpkpConfigIncludeSubDomains)
request.secure = true
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['Public-Key-Pins-Report-Only' : 'max-age=5184000 ; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=" ; includeSubDomains']
}
@EnableWebSecurity
static class HpkpConfigIncludeSubDomains extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.httpPublicKeyPinning()
.addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=")
.includeSubDomains(true)
}
}
def "headers.hpkp with report URI"() {
setup:
loadConfig(HpkpConfigWithReportURI)
request.secure = true
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['Public-Key-Pins-Report-Only' : 'max-age=5184000 ; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=" ; report-uri="https://example.net/pkp-report"']
}
@EnableWebSecurity
static class HpkpConfigWithReportURI extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.httpPublicKeyPinning()
.addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=")
.reportUri(new URI("https://example.net/pkp-report"))
}
}
def "headers.hpkp with report URI as String"() {
setup:
loadConfig(HpkpConfigWithReportURIAsString)
request.secure = true
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['Public-Key-Pins-Report-Only' : 'max-age=5184000 ; pin-sha256="d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=" ; report-uri="https://example.net/pkp-report"']
}
@EnableWebSecurity
static class HpkpConfigWithReportURIAsString extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.httpPublicKeyPinning()
.addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=")
.reportUri("https://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("");
}
}
def "headers.referrerPolicy default"() {
setup:
loadConfig(ReferrerPolicyDefaultConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['Referrer-Policy': 'no-referrer']
}
@EnableWebSecurity
static class ReferrerPolicyDefaultConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.referrerPolicy();
}
}
def "headers.referrerPolicy custom"() {
setup:
loadConfig(ReferrerPolicyCustomConfig)
when:
springSecurityFilterChain.doFilter(request,response,chain)
then:
responseHeaders == ['Referrer-Policy': 'same-origin']
}
@EnableWebSecurity
static class ReferrerPolicyCustomConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.referrerPolicy(ReferrerPolicy.SAME_ORIGIN);
}
}
def "headers.featurePolicy default header"() {
setup:
loadConfig(FeaturePolicyDefaultConfig)
request.secure = true
when:
springSecurityFilterChain.doFilter(request, response, chain)
then:
responseHeaders == ['Feature-Policy': 'geolocation \'self\'']
}
@EnableWebSecurity
static class FeaturePolicyDefaultConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.featurePolicy("geolocation 'self'");
}
}
def "headers.featurePolicy empty policyDirectives"() {
when:
loadConfig(FeaturePolicyInvalidConfig)
then:
thrown(BeanCreationException)
}
@EnableWebSecurity
static class FeaturePolicyInvalidConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.featurePolicy("");
}
}
@EnableWebSecurity
static class HstsWithPreloadConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.headers()
.defaultsDisabled()
.httpStrictTransportSecurity()
.preload(true)
}
}
def "headers.hstsWithPreload"() {
setup:
loadConfig(HstsWithPreloadConfig)
request.secure = true
when:
springSecurityFilterChain.doFilter(request, response, chain)
then:
responseHeaders == ['Strict-Transport-Security': 'max-age=31536000 ; includeSubDomains ; preload']
}
}

View File

@ -0,0 +1,659 @@
/*
* Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.security.config.annotation.web.configurers;
import com.google.common.net.HttpHeaders;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.test.SpringTestRule;
import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter.ReferrerPolicy;
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter.XFrameOptionsMode;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import java.net.URI;
import java.util.LinkedHashMap;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
/**
* Tests for {@link HeadersConfigurer}.
*
* @author Rob Winch
* @author Tim Ysewyn
* @author Joe Grandja
* @author Eddú Meléndez
* @author Vedran Pavic
* @author Eleftheria Stein
*/
public class HeadersConfigurerTests {
@Rule
public final SpringTestRule spring = new SpringTestRule();
@Autowired
MockMvc mvc;
@Test
public void getWhenHeadersConfiguredThenDefaultHeadersInResponse() throws Exception {
this.spring.register(HeadersConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.X_CONTENT_TYPE_OPTIONS, "nosniff"))
.andExpect(header().string(HttpHeaders.X_FRAME_OPTIONS, XFrameOptionsMode.DENY.name()))
.andExpect(header().string(HttpHeaders.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains"))
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"))
.andExpect(header().string(HttpHeaders.EXPIRES, "0"))
.andExpect(header().string(HttpHeaders.PRAGMA, "no-cache"))
.andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "1; mode=block"))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactlyInAnyOrder(
HttpHeaders.X_CONTENT_TYPE_OPTIONS, HttpHeaders.X_FRAME_OPTIONS, HttpHeaders.STRICT_TRANSPORT_SECURITY,
HttpHeaders.CACHE_CONTROL, HttpHeaders.EXPIRES, HttpHeaders.PRAGMA, HttpHeaders.X_XSS_PROTECTION);
}
@EnableWebSecurity
static class HeadersConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers();
// @formatter:on
}
}
@Test
public void getWhenHeaderDefaultsDisabledAndContentTypeConfiguredThenOnlyContentTypeHeaderInResponse()
throws Exception {
this.spring.register(ContentTypeOptionsConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/"))
.andExpect(header().string(HttpHeaders.X_CONTENT_TYPE_OPTIONS, "nosniff"))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.X_CONTENT_TYPE_OPTIONS);
}
@EnableWebSecurity
static class ContentTypeOptionsConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.defaultsDisabled()
.contentTypeOptions();
// @formatter:on
}
}
@Test
public void getWhenHeaderDefaultsDisabledAndFrameOptionsConfiguredThenOnlyFrameOptionsHeaderInResponse()
throws Exception {
this.spring.register(FrameOptionsConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/"))
.andExpect(header().string(HttpHeaders.X_FRAME_OPTIONS, XFrameOptionsMode.DENY.name()))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.X_FRAME_OPTIONS);
}
@EnableWebSecurity
static class FrameOptionsConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.defaultsDisabled()
.frameOptions();
// @formatter:on
}
}
@Test
public void getWhenHeaderDefaultsDisabledAndHstsConfiguredThenOnlyStrictTransportSecurityHeaderInResponse()
throws Exception {
this.spring.register(HstsConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.STRICT_TRANSPORT_SECURITY, "max-age=31536000 ; includeSubDomains"))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.STRICT_TRANSPORT_SECURITY);
}
@EnableWebSecurity
static class HstsConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.defaultsDisabled()
.httpStrictTransportSecurity();
// @formatter:on
}
}
@Test
public void getWhenHeaderDefaultsDisabledAndCacheControlConfiguredThenCacheControlAndExpiresAndPragmaHeadersInResponse()
throws Exception {
this.spring.register(CacheControlConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.CACHE_CONTROL, "no-cache, no-store, max-age=0, must-revalidate"))
.andExpect(header().string(HttpHeaders.EXPIRES, "0"))
.andExpect(header().string(HttpHeaders.PRAGMA, "no-cache"))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactlyInAnyOrder(HttpHeaders.CACHE_CONTROL,
HttpHeaders.EXPIRES, HttpHeaders.PRAGMA);
}
@EnableWebSecurity
static class CacheControlConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.defaultsDisabled()
.cacheControl();
// @formatter:on
}
}
@Test
public void getWhenHeaderDefaultsDisabledAndXssProtectionConfiguredThenOnlyXssProtectionHeaderInResponse()
throws Exception {
this.spring.register(XssProtectionConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.X_XSS_PROTECTION, "1; mode=block"))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.X_XSS_PROTECTION);
}
@EnableWebSecurity
static class XssProtectionConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.defaultsDisabled()
.xssProtection();
// @formatter:on
}
}
@Test
public void getWhenFrameOptionsSameOriginConfiguredThenFrameOptionsHeaderHasValueSameOrigin() throws Exception {
this.spring.register(HeadersCustomSameOriginConfig.class).autowire();
this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.X_FRAME_OPTIONS, XFrameOptionsMode.SAMEORIGIN.name()))
.andReturn();
}
@EnableWebSecurity
static class HeadersCustomSameOriginConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.frameOptions().sameOrigin();
// @formatter:on
}
}
@Test
public void getWhenHeaderDefaultsDisabledAndPublicHpkpWithNoPinThenNoHeadersInResponse() throws Exception {
this.spring.register(HpkpConfigNoPins.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/"))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).isEmpty();
}
@EnableWebSecurity
static class HpkpConfigNoPins extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.defaultsDisabled()
.httpPublicKeyPinning();
// @formatter:on
}
}
@Test
public void getWhenSecureRequestAndHpkpWithPinThenPublicKeyPinsReportOnlyHeaderInResponse()
throws Exception {
this.spring.register(HpkpConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\""))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
}
@Test
public void getWhenInsecureRequestHeaderDefaultsDisabledAndHpkpWithPinThenNoHeadersInResponse()
throws Exception {
this.spring.register(HpkpConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/"))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).isEmpty();
}
@EnableWebSecurity
static class HpkpConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.defaultsDisabled()
.httpPublicKeyPinning()
.addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=");
// @formatter:on
}
}
@Test
public void getWhenHpkpWithMultiplePinsThenPublicKeyPinsReportOnlyHeaderWithMultiplePinsInResponse()
throws Exception {
this.spring.register(HpkpConfigWithPins.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; pin-sha256=\"E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=\""))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
}
@EnableWebSecurity
static class HpkpConfigWithPins extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
Map<String, String> pins = new LinkedHashMap<>();
pins.put("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=", "sha256");
pins.put("E9CZ9INDbd+2eRQozYqqbQ2yXLVKB9+xcprMF+44U1g=", "sha256");
// @formatter:off
http
.headers()
.defaultsDisabled()
.httpPublicKeyPinning()
.withPins(pins);
// @formatter:on
}
}
@Test
public void getWhenHpkpWithCustomAgeThenPublicKeyPinsReportOnlyHeaderWithCustomAgeInResponse() throws Exception {
this.spring.register(HpkpConfigCustomAge.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
"max-age=604800 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\""))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
}
@EnableWebSecurity
static class HpkpConfigCustomAge extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.defaultsDisabled()
.httpPublicKeyPinning()
.addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=")
.maxAgeInSeconds(604800);
// @formatter:on
}
}
@Test
public void getWhenHpkpWithReportOnlyFalseThenPublicKeyPinsHeaderInResponse() throws Exception {
this.spring.register(HpkpConfigTerminateConnection.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.PUBLIC_KEY_PINS,
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\""))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS);
}
@EnableWebSecurity
static class HpkpConfigTerminateConnection extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.defaultsDisabled()
.httpPublicKeyPinning()
.addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=")
.reportOnly(false);
// @formatter:on
}
}
@Test
public void getWhenHpkpIncludeSubdomainThenPublicKeyPinsReportOnlyHeaderWithIncludeSubDomainsInResponse()
throws Exception {
this.spring.register(HpkpConfigIncludeSubDomains.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; includeSubDomains"))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
}
@EnableWebSecurity
static class HpkpConfigIncludeSubDomains extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.defaultsDisabled()
.httpPublicKeyPinning()
.addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=")
.includeSubDomains(true);
// @formatter:on
}
}
@Test
public void getWhenHpkpWithReportUriThenPublicKeyPinsReportOnlyHeaderWithReportUriInResponse() throws Exception {
this.spring.register(HpkpConfigWithReportURI.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; report-uri=\"https://example.net/pkp-report\""))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
}
@EnableWebSecurity
static class HpkpConfigWithReportURI extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.defaultsDisabled()
.httpPublicKeyPinning()
.addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=")
.reportUri(new URI("https://example.net/pkp-report"));
// @formatter:on
}
}
@Test
public void getWhenHpkpWithReportUriAsStringThenPublicKeyPinsReportOnlyHeaderWithReportUriInResponse()
throws Exception {
this.spring.register(HpkpConfigWithReportURIAsString.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY,
"max-age=5184000 ; pin-sha256=\"d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=\" ; report-uri=\"https://example.net/pkp-report\""))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.PUBLIC_KEY_PINS_REPORT_ONLY);
}
@EnableWebSecurity
static class HpkpConfigWithReportURIAsString extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.defaultsDisabled()
.httpPublicKeyPinning()
.addSha256Pins("d6qzRu9zOECb90Uez27xWltNsj0e1Md7GkYYkVoZWmM=")
.reportUri("https://example.net/pkp-report");
// @formatter:on
}
}
@Test
public void getWhenContentSecurityPolicyConfiguredThenContentSecurityPolicyHeaderInResponse() throws Exception {
this.spring.register(ContentSecurityPolicyDefaultConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.CONTENT_SECURITY_POLICY, "default-src 'self'"))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY);
}
@EnableWebSecurity
static class ContentSecurityPolicyDefaultConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.defaultsDisabled()
.contentSecurityPolicy("default-src 'self'");
// @formatter:on
}
}
@Test
public void getWhenContentSecurityPolicyWithReportOnlyThenContentSecurityPolicyReportOnlyHeaderInResponse() throws Exception {
this.spring.register(ContentSecurityPolicyReportOnlyConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY,
"default-src 'self'; script-src trustedscripts.example.com"))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.CONTENT_SECURITY_POLICY_REPORT_ONLY);
}
@EnableWebSecurity
static class ContentSecurityPolicyReportOnlyConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.defaultsDisabled()
.contentSecurityPolicy("default-src 'self'; script-src trustedscripts.example.com")
.reportOnly();
// @formatter:on
}
}
@Test
public void configureWhenContentSecurityPolicyEmptyThenException() {
assertThatThrownBy(() -> this.spring.register(ContentSecurityPolicyInvalidConfig.class).autowire())
.isInstanceOf(BeanCreationException.class)
.hasRootCauseInstanceOf(IllegalArgumentException.class);
}
@EnableWebSecurity
static class ContentSecurityPolicyInvalidConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.defaultsDisabled()
.contentSecurityPolicy("");
// @formatter:on
}
}
@Test
public void getWhenReferrerPolicyConfiguredThenReferrerPolicyHeaderInResponse() throws Exception {
this.spring.register(ReferrerPolicyDefaultConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string("Referrer-Policy", ReferrerPolicy.NO_REFERRER.getPolicy()))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Referrer-Policy");
}
@EnableWebSecurity
static class ReferrerPolicyDefaultConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.defaultsDisabled()
.referrerPolicy();
// @formatter:on
}
}
@Test
public void getWhenReferrerPolicyConfiguredWithCustomValueThenReferrerPolicyHeaderWithCustomValueInResponse()
throws Exception {
this.spring.register(ReferrerPolicyCustomConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string("Referrer-Policy", ReferrerPolicy.SAME_ORIGIN.getPolicy()))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Referrer-Policy");
}
@EnableWebSecurity
static class ReferrerPolicyCustomConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.defaultsDisabled()
.referrerPolicy(ReferrerPolicy.SAME_ORIGIN);
// @formatter:on
}
}
@Test
public void getWhenFeaturePolicyConfiguredThenFeaturePolicyHeaderInResponse() throws Exception {
this.spring.register(FeaturePolicyConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string("Feature-Policy", "geolocation 'self'"))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Feature-Policy");
}
@EnableWebSecurity
static class FeaturePolicyConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.defaultsDisabled()
.featurePolicy("geolocation 'self'");
// @formatter:on
}
}
@Test
public void configureWhenFeaturePolicyEmptyThenException() {
assertThatThrownBy(() -> this.spring.register(FeaturePolicyInvalidConfig.class).autowire())
.isInstanceOf(BeanCreationException.class)
.hasRootCauseInstanceOf(IllegalArgumentException.class);
}
@EnableWebSecurity
static class FeaturePolicyInvalidConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.defaultsDisabled()
.featurePolicy("");
// @formatter:on
}
}
@Test
public void getWhenHstsConfiguredWithPreloadThenStrictTransportSecurityHeaderWithPreloadInResponse()
throws Exception {
this.spring.register(HstsWithPreloadConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
.andExpect(header().string(HttpHeaders.STRICT_TRANSPORT_SECURITY,
"max-age=31536000 ; includeSubDomains ; preload"))
.andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.STRICT_TRANSPORT_SECURITY);
}
@EnableWebSecurity
static class HstsWithPreloadConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.headers()
.defaultsDisabled()
.httpStrictTransportSecurity()
.preload(true);
// @formatter:on
}
}
}