2 changed files with 659 additions and 568 deletions
@ -1,568 +0,0 @@
@@ -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'] |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,659 @@
@@ -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
|
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue