浏览代码

Add Referrer-Policy header support

Fixes gh-4110
Eddú Meléndez 8 年之前
父节点
当前提交
23294c4c57

+ 1 - 1
config/src/main/java/org/springframework/security/config/SecurityNamespaceHandler.java

@@ -221,7 +221,7 @@ public final class SecurityNamespaceHandler implements NamespaceHandler {
 	private boolean matchesVersionInternal(Element element) {
 		String schemaLocation = element.getAttributeNS(
 				"http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
-		return schemaLocation.matches("(?m).*spring-security-4\\.1.*.xsd.*")
+		return schemaLocation.matches("(?m).*spring-security-4\\.2.*.xsd.*")
 				|| schemaLocation.matches("(?m).*spring-security.xsd.*")
 				|| !schemaLocation.matches("(?m).*spring-security.*");
 	}

+ 69 - 0
config/src/main/java/org/springframework/security/config/annotation/web/configurers/HeadersConfigurer.java

@@ -28,6 +28,7 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
 import org.springframework.security.web.header.HeaderWriter;
 import org.springframework.security.web.header.HeaderWriterFilter;
 import org.springframework.security.web.header.writers.*;
+import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter.ReferrerPolicy;
 import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter;
 import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter.XFrameOptionsMode;
 import org.springframework.security.web.util.matcher.RequestMatcher;
@@ -56,6 +57,7 @@ import org.springframework.util.Assert;
  * @author Rob Winch
  * @author Tim Ysewyn
  * @author Joe Grandja
+ * @author Eddú Meléndez
  * @since 3.2
  */
 public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
@@ -78,6 +80,8 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
 
 	private final ContentSecurityPolicyConfig contentSecurityPolicy = new ContentSecurityPolicyConfig();
 
+	private final ReferrerPolicyConfig referrerPolicy = new ReferrerPolicyConfig();
+
 	/**
 	 * Creates a new instance
 	 *
@@ -770,6 +774,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
 		addIfNotNull(writers, frameOptions.writer);
 		addIfNotNull(writers, hpkp.writer);
 		addIfNotNull(writers, contentSecurityPolicy.writer);
+		addIfNotNull(writers, referrerPolicy.writer);
 		writers.addAll(headerWriters);
 		return writers;
 	}
@@ -779,4 +784,68 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>> extends
 			values.add(value);
 		}
 	}
+
+	/**
+	 * <p>
+	 * Allows configuration for <a href="https://www.w3.org/TR/referrer-policy/">Referrer Policy</a>.
+	 * </p>
+	 *
+	 * <p>
+	 * Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support the writing
+	 * of the header as detailed in the W3C Technical Report:
+	 * </p>
+	 * <ul>
+	 *  <li>Referrer-Policy</li>
+	 * </ul>
+	 *
+	 * <p>Default value is:</p>
+	 *
+	 * <pre>
+	 * Referrer-Policy: no-referrer
+	 * </pre>
+	 *
+	 * @see ReferrerPolicyHeaderWriter
+	 * @since 4.2
+	 * @return the ReferrerPolicyConfig for additional configuration
+	 */
+	public ReferrerPolicyConfig referrerPolicy() {
+		this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter();
+		return this.referrerPolicy;
+	}
+
+	/**
+	 * <p>
+	 * Allows configuration for <a href="https://www.w3.org/TR/referrer-policy/">Referrer Policy</a>.
+	 * </p>
+	 *
+	 * <p>
+	 * Configuration is provided to the {@link ReferrerPolicyHeaderWriter} which support the writing
+	 * of the header as detailed in the W3C Technical Report:
+	 * </p>
+	 * <ul>
+	 *  <li>Referrer-Policy</li>
+	 * </ul>
+	 *
+	 * @see ReferrerPolicyHeaderWriter
+	 * @since 4.2
+	 * @return the ReferrerPolicyConfig for additional configuration
+	 * @throws IllegalArgumentException if policy is null or empty
+	 */
+	public ReferrerPolicyConfig referrerPolicy(ReferrerPolicy policy) {
+		this.referrerPolicy.writer = new ReferrerPolicyHeaderWriter(policy);
+		return this.referrerPolicy;
+	}
+
+	public final class ReferrerPolicyConfig {
+
+		private ReferrerPolicyHeaderWriter writer;
+
+		private ReferrerPolicyConfig() {
+		}
+
+		public HeadersConfigurer<H> and() {
+			return HeadersConfigurer.this;
+		}
+
+	}
 }

+ 22 - 0
config/src/main/java/org/springframework/security/config/http/HeadersBeanDefinitionParser.java

@@ -31,6 +31,7 @@ import org.springframework.beans.factory.xml.BeanDefinitionParser;
 import org.springframework.beans.factory.xml.ParserContext;
 import org.springframework.security.web.header.HeaderWriterFilter;
 import org.springframework.security.web.header.writers.*;
+import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter.ReferrerPolicy;
 import org.springframework.security.web.header.writers.frameoptions.RegExpAllowFromStrategy;
 import org.springframework.security.web.header.writers.frameoptions.StaticAllowFromStrategy;
 import org.springframework.security.web.header.writers.frameoptions.WhiteListedAllowFromStrategy;
@@ -45,6 +46,7 @@ import org.w3c.dom.Node;
  *
  * @author Marten Deinum
  * @author Tim Ysewyn
+ * @author Eddú Meléndez
  * @since 3.2
  */
 public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
@@ -82,6 +84,7 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
 	private static final String GENERIC_HEADER_ELEMENT = "header";
 
 	private static final String CONTENT_SECURITY_POLICY_ELEMENT = "content-security-policy";
+	private static final String REFERRER_POLICY_ELEMENT = "referrer-policy";
 
 	private static final String ALLOW_FROM = "ALLOW-FROM";
 
@@ -109,6 +112,8 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
 
 		parseContentSecurityPolicyElement(disabled, element, parserContext);
 
+		parseReferrerPolicyElement(element, parserContext);
+
 		parseHeaderElements(element);
 
 		boolean noWriters = headerWriters.isEmpty();
@@ -291,6 +296,23 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
 		headerWriters.add(headersWriter.getBeanDefinition());
 	}
 
+	private void parseReferrerPolicyElement(Element element, ParserContext context) {
+		Element referrerPolicyElement = (element == null) ? null : DomUtils.getChildElementByTagName(element, REFERRER_POLICY_ELEMENT);
+		if (referrerPolicyElement != null) {
+			addReferrerPolicy(referrerPolicyElement, context);
+		}
+	}
+
+	private void addReferrerPolicy(Element referrerPolicyElement, ParserContext context) {
+		BeanDefinitionBuilder headersWriter = BeanDefinitionBuilder.genericBeanDefinition(ReferrerPolicyHeaderWriter.class);
+
+		String policy = referrerPolicyElement.getAttribute(ATT_POLICY);
+		if (StringUtils.hasLength(policy)) {
+			headersWriter.addConstructorArgValue(ReferrerPolicy.get(policy));
+		}
+		headerWriters.add(headersWriter.getBeanDefinition());
+	}
+
 	private void attrNotAllowed(ParserContext context, String attrName,
 			String otherAttrName, Element element) {
 		context.getReaderContext().error(

+ 8 - 1
config/src/main/resources/org/springframework/security/config/spring-security-4.2.rnc

@@ -753,7 +753,7 @@ csrf-options.attlist &=
 
 headers =
 ## Element for configuration of the HeaderWritersFilter. Enables easy setting for the X-Frame-Options, X-XSS-Protection and X-Content-Type-Options headers.
-element headers { headers-options.attlist, (cache-control? & xss-protection? & hsts? & frame-options? & content-type-options? & hpkp? & content-security-policy? & header*)}
+element headers { headers-options.attlist, (cache-control? & xss-protection? & hsts? & frame-options? & content-type-options? & hpkp? & content-security-policy? & referrer-policy? & header*)}
 headers-options.attlist &=
 	## Specifies if the default headers should be disabled. Default false.
 	attribute defaults-disabled {xsd:boolean}?
@@ -824,6 +824,13 @@ csp-options.attlist &=
 	## Set to true, to enable the Content-Security-Policy-Report-Only header for reporting policy violations only. Defaults to false.
 	attribute report-only {xsd:boolean}?
 
+referrer-policy =
+	## Adds support for Referrer Policy
+	element referrer-policy {referrer-options.attlist}
+referrer-options.attlist &=
+	## The policies for the Referrer-Policy header.
+	attribute policy {"no-referrer","no-referrer-when-downgrade","same-origin","origin","strict-origin","origin-when-cross-origin","strict-origin-when-cross-origin","unsafe-url"}?
+
 cache-control =
 	## Adds Cache-Control no-cache, no-store, must-revalidate, Pragma no-cache, and Expires 0 for every request
 	element cache-control {cache-control.attlist}

+ 30 - 0
config/src/main/resources/org/springframework/security/config/spring-security-4.2.xsd

@@ -2357,6 +2357,7 @@
             <xs:element ref="security:content-type-options"/>
             <xs:element ref="security:hpkp"/>
             <xs:element ref="security:content-security-policy"/>
+            <xs:element ref="security:referrer-policy"/>
             <xs:element ref="security:header"/>
          </xs:choice>
          <xs:attributeGroup ref="security:headers-options.attlist"/>
@@ -2539,6 +2540,35 @@
          </xs:annotation>
       </xs:attribute>
   </xs:attributeGroup>
+  <xs:element name="referrer-policy">
+      <xs:annotation>
+         <xs:documentation>Adds support for Referrer Policy
+                </xs:documentation>
+      </xs:annotation>
+      <xs:complexType>
+         <xs:attributeGroup ref="security:referrer-options.attlist"/>
+      </xs:complexType>
+   </xs:element>
+  <xs:attributeGroup name="referrer-options.attlist">
+      <xs:attribute name="policy">
+         <xs:annotation>
+            <xs:documentation>The policies for the Referrer-Policy header.
+                </xs:documentation>
+         </xs:annotation>
+         <xs:simpleType>
+            <xs:restriction base="xs:token">
+               <xs:enumeration value="no-referrer"/>
+               <xs:enumeration value="no-referrer-when-downgrade"/>
+               <xs:enumeration value="same-origin"/>
+               <xs:enumeration value="origin"/>
+               <xs:enumeration value="strict-origin"/>
+               <xs:enumeration value="origin-when-cross-origin"/>
+               <xs:enumeration value="strict-origin-when-cross-origin"/>
+               <xs:enumeration value="unsafe-url"/>
+            </xs:restriction>
+         </xs:simpleType>
+      </xs:attribute>
+  </xs:attributeGroup>
   <xs:element name="cache-control">
       <xs:annotation>
          <xs:documentation>Adds Cache-Control no-cache, no-store, must-revalidate, Pragma no-cache, and Expires 0 for

+ 44 - 0
config/src/test/groovy/org/springframework/security/config/annotation/web/configurers/HeadersConfigurerTests.groovy

@@ -20,12 +20,14 @@ 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
 
 /**
  *
  * @author Rob Winch
  * @author Tim Ysewyn
  * @author Joe Grandja
+ * @author Eddú Meléndez
  */
 class HeadersConfigurerTests extends BaseSpringSpec {
 
@@ -453,4 +455,46 @@ class HeadersConfigurerTests extends BaseSpringSpec {
 		}
 	}
 
+	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);
+		}
+	}
+
 }

+ 32 - 0
config/src/test/groovy/org/springframework/security/config/http/HttpHeadersConfigTests.groovy

@@ -920,6 +920,38 @@ class HttpHeadersConfigTests extends AbstractHttpConfigTests {
 			assertHeaders(response, expectedHeaders)
 	}
 
+	def 'http headers defaults : referrer-policy'() {
+		setup:
+			httpAutoConfig {
+				'headers'('defaults-disabled':true) {
+					'referrer-policy'()
+				}
+			}
+			createAppContext()
+		when:
+			def hf = getFilter(HeaderWriterFilter)
+			MockHttpServletResponse response = new MockHttpServletResponse()
+			hf.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
+		then:
+			assertHeaders(response, ['Referrer-Policy': 'no-referrer'])
+	}
+
+	def 'http headers defaults : referrer-policy same-origin'() {
+		setup:
+			httpAutoConfig {
+				'headers'('defaults-disabled':true) {
+					'referrer-policy'('policy': 'same-origin')
+				}
+			}
+			createAppContext()
+		when:
+			def hf = getFilter(HeaderWriterFilter)
+			MockHttpServletResponse response = new MockHttpServletResponse()
+			hf.doFilter(new MockHttpServletRequest(), response, new MockFilterChain())
+		then:
+			assertHeaders(response, ['Referrer-Policy': 'same-origin'])
+	}
+
 	def assertHeaders(MockHttpServletResponse response, Map<String,String> expected) {
 		assert response.headerNames == expected.keySet()
 		expected.each { headerName, value ->

+ 1 - 1
config/src/test/java/org/springframework/security/config/util/InMemoryXmlApplicationContext.java

@@ -40,7 +40,7 @@ public class InMemoryXmlApplicationContext extends AbstractXmlApplicationContext
 			+ "http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-";
 	static final String BEANS_CLOSE = "</b:beans>\n";
 
-	static final String SPRING_SECURITY_VERSION = "4.1";
+	static final String SPRING_SECURITY_VERSION = "4.2";
 
 	Resource inMemoryXml;
 

+ 71 - 0
docs/manual/src/docs/asciidoc/index.adoc

@@ -4353,6 +4353,57 @@ protected void configure(HttpSecurity http) throws Exception {
 }
 ----
 
+[[headers-referrer]]
+==== Referrer Policy
+
+https://www.w3.org/TR/referrer-policy[Referrer Policy] is a mechanism that web applications can leverage to manage the referrer field, which contains the last
+page the user was on.
+
+Spring Security's approach is to use https://www.w3.org/TR/referrer-policy/[Referrer Policy] header, which provides different https://www.w3.org/TR/referrer-policy/#referrer-policies[policies]:
+
+[source]
+----
+Referrer-Policy: same-origin
+----
+
+The Referrer-Policy response header instructs the browser to let the destination knows the source where the user was previously.
+
+[[headers-referrer-configure]]
+===== Configuring Referrer Policy
+
+Spring Security *_doesn't add_* Referrer Policy header by default.
+
+You can enable the Referrer-Policy header using XML configuration with the <<nsa-referrer-policy,<referrer-policy>>> element as shown below:
+
+[source,xml]
+----
+<http>
+	<!-- ... -->
+
+	<headers>
+		<referrer-policy policy="same-origin" />
+	</headers>
+</http>
+----
+
+Similarly, you can enable the Referrer Policy header using Java configuration as shown below:
+
+[source,java]
+----
+@EnableWebSecurity
+public class WebSecurityConfig extends
+WebSecurityConfigurerAdapter {
+
+@Override
+protected void configure(HttpSecurity http) throws Exception {
+	http
+	// ...
+	.headers()
+		.referrerPolicy(ReferrerPolicy.SAME_ORIGIN);
+}
+}
+----
+
 [[headers-csp-links]]
 ===== Additional Resources
 
@@ -7685,6 +7736,7 @@ This element allows for configuring additional (security) headers to be send wit
 ** `X-Content-Type-Options` - Can be set using the <<nsa-content-type-options,content-type-options>> element. The http://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx[X-Content-Type-Options] header prevents Internet Explorer from MIME-sniffing a response away from the declared content-type. This also applies to Google Chrome, when downloading extensions.
 ** `Public-Key-Pinning` or `Public-Key-Pinning-Report-Only` - Can be set using the <<nsa-hpkp,hpkp>> element. This allows HTTPS websites to resist impersonation by attackers using mis-issued or otherwise fraudulent certificates.
 ** `Content-Security-Policy` or `Content-Security-Policy-Report-Only` - Can be set using the <<nsa-content-security-policy,content-security-policy>> element. https://www.w3.org/TR/CSP2/[Content Security Policy (CSP)] is a mechanism that web applications can leverage to mitigate content injection vulnerabilities, such as cross-site scripting (XSS).
+** `Referrer-Policy` - Can be set using the <<nsa-referrer-policy,referrer-policy>> element, https://www.w3.org/TR/referrer-policy/[Referrer-Policy] is a mechanism that web applications can leverage to manage the referrer field, which contains the last page the user was on.
 
 [[nsa-headers-attributes]]
 ===== <headers> Attributes
@@ -7718,6 +7770,7 @@ Optional attribute that specifies to disable Spring Security's HTTP response hea
 * <<nsa-header,header>>
 * <<nsa-hpkp,hpkp>>
 * <<nsa-hsts,hsts>>
+* <<nsa-referrer-policy,referrer-policy>>
 * <<nsa-xss-protection,xss-protection>>
 
 
@@ -7867,6 +7920,24 @@ Set to true, to enable the Content-Security-Policy-Report-Only header for report
 
 
 
+[[nsa-referrer-policy]]
+==== <referrer-policy>
+When enabled adds the https://www.w3.org/TR/referrer-policy/[Referrer Policy] header to the response.
+
+[[nsa-referrer-policy-attributes]]
+===== <referrer-policy> Attributes
+
+[[nsa-referrer-policy-policy]]
+*  **policy**
+The policy for the Referrer-Policy header. Default "no-referrer".
+
+[[nsa-referrer-policy-parents]]
+===== Parent Elements of <referrer-policy>
+
+* <<nsa-headers,headers>>
+
+
+
 [[nsa-frame-options]]
 ==== <frame-options>
 When enabled adds the http://tools.ietf.org/html/draft-ietf-websec-x-frame-options[X-Frame-Options header] to the response, this allows newer browsers to do some security checks and prevent http://en.wikipedia.org/wiki/Clickjacking[clickjacking] attacks.

+ 129 - 0
web/src/main/java/org/springframework/security/web/header/writers/ReferrerPolicyHeaderWriter.java

@@ -0,0 +1,129 @@
+/*
+ * Copyright 2002-2016 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
+ *
+ *      http://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.web.header.writers;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.springframework.security.web.header.HeaderWriter;
+import org.springframework.util.Assert;
+
+/**
+ * <p>
+ * Provides support for <a href="https://www.w3.org/TR/referrer-policy/">Referrer Policy</a>.
+ * </p>
+ *
+ * <p>
+ * The list of policies defined can be found at
+ * <a href="https://www.w3.org/TR/referrer-policy/#referrer-policies">Referrer Policies</a>.
+ * </p>
+ *
+ * <p>
+ * This implementation of {@link HeaderWriter} writes the following header:
+ * </p>
+ * <ul>
+ *  <li>Referrer-Policy</li>
+ * </ul>
+ *
+ * <p>
+ * By default, the Referrer-Policy header is not included in the response.
+ * Policy <b>no-referrer</b> is used by default if no {@link ReferrerPolicy} is set.
+ * </p>
+ *
+ * @author Eddú Meléndez
+ * @since 4.2
+ */
+public class ReferrerPolicyHeaderWriter implements HeaderWriter {
+
+	private final String REFERER_POLICY_HEADER = "Referrer-Policy";
+
+	private ReferrerPolicy policy;
+
+	/**
+	 * Creates a new instance. Default value: no-referrer.
+	 */
+	public ReferrerPolicyHeaderWriter() {
+		this(ReferrerPolicy.NO_REFERRER);
+	}
+
+	/**
+	 * Creates a new instance.
+	 *
+	 * @param policy
+	 * @throws IllegalArgumentException if policyDirectives is null or empty
+	 */
+	public ReferrerPolicyHeaderWriter(ReferrerPolicy policy) {
+		setPolicy(policy);
+	}
+
+	/**
+	 * Sets the policy to be used in the response header.
+	 * @param policy
+	 */
+	public void setPolicy(ReferrerPolicy policy) {
+		Assert.notNull(policy, "policy can not be null");
+		this.policy = policy;
+	}
+
+	/**
+	 * @see org.springframework.security.web.header.HeaderWriter#writeHeaders(HttpServletRequest, HttpServletResponse)
+	 */
+	@Override
+	public void writeHeaders(HttpServletRequest request, HttpServletResponse response) {
+		response.setHeader(REFERER_POLICY_HEADER, this.policy.getPolicy());
+	}
+
+	public enum ReferrerPolicy {
+
+		NO_REFERRER("no-referrer"),
+		NO_REFERRER_WHEN_DOWNGRADE("no-referrer-when-downgrade"),
+		SAME_ORIGIN("same-origin"),
+		ORIGIN("origin"),
+		STRICT_ORIGIN("strict-origin"),
+		ORIGIN_WHEN_CROSS_ORIGIN("origin-when-cross-origin"),
+		STRICT_ORIGIN_WHEN_CROSS_ORIGIN("strict-origin-when-cross-origin"),
+		UNSAFE_URL("unsafe-url");
+
+		private static Map<String, ReferrerPolicy> REFERRER_POLICIES;
+
+		static {
+			Map<String, ReferrerPolicy> referrerPolicies = new HashMap<String, ReferrerPolicy>();
+			for (ReferrerPolicy referrerPolicy : values()) {
+				referrerPolicies.put(referrerPolicy.getPolicy(), referrerPolicy);
+			}
+			REFERRER_POLICIES = Collections.unmodifiableMap(referrerPolicies);
+		}
+
+		private String policy;
+
+		private ReferrerPolicy(String policy) {
+			this.policy = policy;
+		}
+
+		public String getPolicy() {
+			return this.policy;
+		}
+
+		public static ReferrerPolicy get(String referrerPolicy) {
+			return REFERRER_POLICIES.get(referrerPolicy);
+		}
+	}
+
+}

+ 68 - 0
web/src/test/java/org/springframework/security/web/header/writers/ReferrerPolicyHeaderWriterTests.java

@@ -0,0 +1,68 @@
+/*
+ * Copyright 2002-2016 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
+ *
+ *      http://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.web.header.writers;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter.*;
+
+/**
+ * @author Eddú Meléndez
+ */
+public class ReferrerPolicyHeaderWriterTests {
+
+	private final String DEFAULT_REFERRER_POLICY = "no-referrer";
+	private MockHttpServletRequest request;
+	private MockHttpServletResponse response;
+	private ReferrerPolicyHeaderWriter writer;
+
+	@Before
+	public void setup() {
+		this.request = new MockHttpServletRequest();
+		this.request.setSecure(true);
+		this.response = new MockHttpServletResponse();
+		this.writer = new ReferrerPolicyHeaderWriter();
+	}
+
+	@Test
+	public void writeHeadersReferrerPolicyDefault() {
+		this.writer.writeHeaders(this.request, this.response);
+
+		assertThat(this.response.getHeaderNames().size()).isEqualTo(1);
+		assertThat(this.response.getHeader("Referrer-Policy")).isEqualTo(DEFAULT_REFERRER_POLICY);
+	}
+
+	@Test
+	public void writeHeadersReferrerPolicyCustom() {
+		this.writer = new ReferrerPolicyHeaderWriter(ReferrerPolicy.SAME_ORIGIN);
+
+		this.writer.writeHeaders(this.request, this.response);
+
+		assertThat(this.response.getHeaderNames().size()).isEqualTo(1);
+		assertThat(this.response.getHeader("Referrer-Policy")).isEqualTo("same-origin");
+	}
+
+	@Test(expected = IllegalArgumentException.class)
+	public void writeHeaderReferrerPolicyInvalid() {
+		this.writer = new ReferrerPolicyHeaderWriter(null);
+	}
+
+}