Add permissionsPolicy http header
This commit is contained in:
parent
48ef27b80a
commit
54d3839f63
|
@ -34,6 +34,7 @@ import org.springframework.security.web.header.writers.ContentSecurityPolicyHead
|
|||
import org.springframework.security.web.header.writers.FeaturePolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.HpkpHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.HstsHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.PermissionsPolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter.ReferrerPolicy;
|
||||
import org.springframework.security.web.header.writers.XContentTypeOptionsHeaderWriter;
|
||||
|
@ -93,6 +94,8 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
|||
|
||||
private final FeaturePolicyConfig featurePolicy = new FeaturePolicyConfig();
|
||||
|
||||
private final PermissionsPolicyConfig permissionsPolicy = new PermissionsPolicyConfig();
|
||||
|
||||
/**
|
||||
* Creates a new instance
|
||||
*
|
||||
|
@ -387,6 +390,7 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
|||
addIfNotNull(writers, this.contentSecurityPolicy.writer);
|
||||
addIfNotNull(writers, this.referrerPolicy.writer);
|
||||
addIfNotNull(writers, this.featurePolicy.writer);
|
||||
addIfNotNull(writers, this.permissionsPolicy.writer);
|
||||
writers.addAll(this.headerWriters);
|
||||
return writers;
|
||||
}
|
||||
|
@ -487,12 +491,58 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
|||
* @throws IllegalArgumentException if policyDirectives is {@code null} or empty
|
||||
* @since 5.1
|
||||
* @see FeaturePolicyHeaderWriter
|
||||
* @deprecated Use {@link #permissionsPolicy(Customizer)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public FeaturePolicyConfig featurePolicy(String policyDirectives) {
|
||||
this.featurePolicy.writer = new FeaturePolicyHeaderWriter(policyDirectives);
|
||||
return this.featurePolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Allows configuration for
|
||||
* <a href="https://w3c.github.io/webappsec-permissions-policy/">Permissions
|
||||
* Policy</a>.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Configuration is provided to the {@link PermissionsPolicyHeaderWriter} which
|
||||
* support the writing of the header as detailed in the W3C Technical Report:
|
||||
* </p>
|
||||
* <ul>
|
||||
* <li>Permissions-Policy</li>
|
||||
* </ul>
|
||||
* @return the {@link PermissionsPolicyConfig} for additional configuration
|
||||
* @since 5.5
|
||||
* @see PermissionsPolicyHeaderWriter
|
||||
*/
|
||||
public PermissionsPolicyConfig permissionsPolicy() {
|
||||
this.permissionsPolicy.writer = new PermissionsPolicyHeaderWriter();
|
||||
return this.permissionsPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for
|
||||
* <a href="https://w3c.github.io/webappsec-permissions-policy/"> Permissions
|
||||
* Policy</a>.
|
||||
* <p>
|
||||
* Calling this method automatically enables (includes) the {@code Permissions-Policy}
|
||||
* header in the response using the supplied policy directive(s).
|
||||
* <p>
|
||||
* Configuration is provided to the {@link PermissionsPolicyHeaderWriter} which is
|
||||
* responsible for writing the header.
|
||||
* @return the {@link PermissionsPolicyConfig} for additional configuration
|
||||
* @throws IllegalArgumentException if policyDirectives is {@code null} or empty
|
||||
* @since 5.5
|
||||
* @see PermissionsPolicyHeaderWriter
|
||||
*/
|
||||
public PermissionsPolicyConfig permissionsPolicy(Customizer<PermissionsPolicyConfig> permissionsPolicyCustomizer) {
|
||||
this.permissionsPolicy.writer = new PermissionsPolicyHeaderWriter();
|
||||
permissionsPolicyCustomizer.customize(this.permissionsPolicy);
|
||||
return this.permissionsPolicy;
|
||||
}
|
||||
|
||||
public final class ContentTypeOptionsConfig {
|
||||
|
||||
private XContentTypeOptionsHeaderWriter writer;
|
||||
|
@ -1063,4 +1113,33 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
|
|||
|
||||
}
|
||||
|
||||
public final class PermissionsPolicyConfig {
|
||||
|
||||
private PermissionsPolicyHeaderWriter writer;
|
||||
|
||||
private PermissionsPolicyConfig() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the policy to be used in the response header.
|
||||
* @param policy a permissions policy
|
||||
* @return the {@link PermissionsPolicyConfig} for additional configuration
|
||||
* @throws IllegalArgumentException if policy is null
|
||||
*/
|
||||
public PermissionsPolicyConfig policy(String policy) {
|
||||
this.writer.setPolicy(policy);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows completing configuration of Permissions Policy and continuing
|
||||
* configuration of headers.
|
||||
* @return the {@link HeadersConfigurer} for additional configuration
|
||||
*/
|
||||
public HeadersConfigurer<H> and() {
|
||||
return HeadersConfigurer.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,6 +39,7 @@ import org.springframework.security.web.header.writers.ContentSecurityPolicyHead
|
|||
import org.springframework.security.web.header.writers.FeaturePolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.HpkpHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.HstsHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.PermissionsPolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter;
|
||||
import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter.ReferrerPolicy;
|
||||
import org.springframework.security.web.header.writers.StaticHeadersWriter;
|
||||
|
@ -119,6 +120,8 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
|||
|
||||
private static final String FEATURE_POLICY_ELEMENT = "feature-policy";
|
||||
|
||||
private static final String PERMISSIONS_POLICY_ELEMENT = "permissions-policy";
|
||||
|
||||
private static final String ALLOW_FROM = "ALLOW-FROM";
|
||||
|
||||
private ManagedList<BeanMetadataElement> headerWriters;
|
||||
|
@ -140,6 +143,7 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
|||
parseContentSecurityPolicyElement(disabled, element, parserContext);
|
||||
parseReferrerPolicyElement(element, parserContext);
|
||||
parseFeaturePolicyElement(element, parserContext);
|
||||
parsePermissionsPolicyElement(element, parserContext);
|
||||
parseHeaderElements(element);
|
||||
boolean noWriters = this.headerWriters.isEmpty();
|
||||
if (disabled && !noWriters) {
|
||||
|
@ -351,6 +355,27 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
|
|||
this.headerWriters.add(headersWriter.getBeanDefinition());
|
||||
}
|
||||
|
||||
private void parsePermissionsPolicyElement(Element element, ParserContext context) {
|
||||
Element permissionsPolicyElement = (element != null)
|
||||
? DomUtils.getChildElementByTagName(element, PERMISSIONS_POLICY_ELEMENT) : null;
|
||||
if (permissionsPolicyElement != null) {
|
||||
addPermissionsPolicy(permissionsPolicyElement, context);
|
||||
}
|
||||
}
|
||||
|
||||
private void addPermissionsPolicy(Element permissionsPolicyElement, ParserContext context) {
|
||||
BeanDefinitionBuilder headersWriter = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(PermissionsPolicyHeaderWriter.class);
|
||||
String policyDirectives = permissionsPolicyElement.getAttribute(ATT_POLICY);
|
||||
if (!StringUtils.hasText(policyDirectives)) {
|
||||
context.getReaderContext().error(ATT_POLICY + " requires a 'value' to be set.", permissionsPolicyElement);
|
||||
}
|
||||
else {
|
||||
headersWriter.addConstructorArgValue(policyDirectives);
|
||||
}
|
||||
this.headerWriters.add(headersWriter.getBeanDefinition());
|
||||
}
|
||||
|
||||
private void attrNotAllowed(ParserContext context, String attrName, String otherAttrName, Element element) {
|
||||
context.getReaderContext().error("Only one of '" + attrName + "' or '" + otherAttrName + "' can be set.",
|
||||
element);
|
||||
|
|
|
@ -149,6 +149,7 @@ import org.springframework.security.web.server.header.ContentSecurityPolicyServe
|
|||
import org.springframework.security.web.server.header.ContentTypeOptionsServerHttpHeadersWriter;
|
||||
import org.springframework.security.web.server.header.FeaturePolicyServerHttpHeadersWriter;
|
||||
import org.springframework.security.web.server.header.HttpHeaderWriterWebFilter;
|
||||
import org.springframework.security.web.server.header.PermissionsPolicyServerHttpHeadersWriter;
|
||||
import org.springframework.security.web.server.header.ReferrerPolicyServerHttpHeadersWriter;
|
||||
import org.springframework.security.web.server.header.ReferrerPolicyServerHttpHeadersWriter.ReferrerPolicy;
|
||||
import org.springframework.security.web.server.header.ServerHttpHeadersWriter;
|
||||
|
@ -2232,13 +2233,16 @@ public class ServerHttpSecurity {
|
|||
|
||||
private FeaturePolicyServerHttpHeadersWriter featurePolicy = new FeaturePolicyServerHttpHeadersWriter();
|
||||
|
||||
private PermissionsPolicyServerHttpHeadersWriter permissionsPolicy = new PermissionsPolicyServerHttpHeadersWriter();
|
||||
|
||||
private ContentSecurityPolicyServerHttpHeadersWriter contentSecurityPolicy = new ContentSecurityPolicyServerHttpHeadersWriter();
|
||||
|
||||
private ReferrerPolicyServerHttpHeadersWriter referrerPolicy = new ReferrerPolicyServerHttpHeadersWriter();
|
||||
|
||||
private HeaderSpec() {
|
||||
this.writers = new ArrayList<>(Arrays.asList(this.cacheControl, this.contentTypeOptions, this.hsts,
|
||||
this.frameOptions, this.xss, this.featurePolicy, this.contentSecurityPolicy, this.referrerPolicy));
|
||||
this.frameOptions, this.xss, this.featurePolicy, this.permissionsPolicy, this.contentSecurityPolicy,
|
||||
this.referrerPolicy));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2395,13 +2399,32 @@ public class ServerHttpSecurity {
|
|||
|
||||
/**
|
||||
* Configures {@code Feature-Policy} response header.
|
||||
* @param policyDirectives the policy directive(s)
|
||||
* @param policyDirectives the policy
|
||||
* @return the {@link FeaturePolicySpec} to configure
|
||||
*/
|
||||
public FeaturePolicySpec featurePolicy(String policyDirectives) {
|
||||
return new FeaturePolicySpec(policyDirectives);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures {@code Permissions-Policy} response header.
|
||||
* @return the {@link PermissionsPolicySpec} to configure
|
||||
*/
|
||||
public PermissionsPolicySpec permissionsPolicy() {
|
||||
return new PermissionsPolicySpec();
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures {@code Permissions-Policy} response header.
|
||||
* @param permissionsPolicyCustomizer the {@link Customizer} to provide more
|
||||
* options for the {@link PermissionsPolicySpec}
|
||||
* @return the {@link HeaderSpec} to customize
|
||||
*/
|
||||
public HeaderSpec permissionsPolicy(Customizer<PermissionsPolicySpec> permissionsPolicyCustomizer) {
|
||||
permissionsPolicyCustomizer.customize(new PermissionsPolicySpec());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures {@code Referrer-Policy} response header.
|
||||
* @param referrerPolicy the policy to use
|
||||
|
@ -2677,6 +2700,38 @@ public class ServerHttpSecurity {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures {@code Permissions-Policy} response header.
|
||||
*
|
||||
* @since 5.5
|
||||
* @see #permissionsPolicy()
|
||||
*/
|
||||
public final class PermissionsPolicySpec {
|
||||
|
||||
private PermissionsPolicySpec() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the policy to be used in the response header.
|
||||
* @param policy a permissions policy
|
||||
* @return the {@link PermissionsPolicySpec} to continue configuring
|
||||
*/
|
||||
public PermissionsPolicySpec policy(String policy) {
|
||||
HeaderSpec.this.permissionsPolicy.setPolicy(policy);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows method chaining to continue configuring the
|
||||
* {@link ServerHttpSecurity}.
|
||||
* @return the {@link HeaderSpec} to continue configuring
|
||||
*/
|
||||
public HeaderSpec and() {
|
||||
return HeaderSpec.this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures {@code Referrer-Policy} response header.
|
||||
*
|
||||
|
|
|
@ -34,6 +34,7 @@ class ServerHeadersDsl {
|
|||
private var contentSecurityPolicy: ((ServerHttpSecurity.HeaderSpec.ContentSecurityPolicySpec) -> Unit)? = null
|
||||
private var referrerPolicy: ((ServerHttpSecurity.HeaderSpec.ReferrerPolicySpec) -> Unit)? = null
|
||||
private var featurePolicyDirectives: String? = null
|
||||
private var permissionsPolicy: ((ServerHttpSecurity.HeaderSpec.PermissionsPolicySpec) -> Unit)? = null
|
||||
|
||||
private var disabled = false
|
||||
|
||||
|
@ -140,6 +141,21 @@ class ServerHeadersDsl {
|
|||
this.featurePolicyDirectives = policyDirectives
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href="https://w3c.github.io/webappsec-permissions-policy/">Permissions
|
||||
* Policy</a>.
|
||||
*
|
||||
* <p>
|
||||
* Calling this method automatically enables (includes) the Permissions-Policy
|
||||
* header in the response using the supplied policy directive(s).
|
||||
* <p>
|
||||
*
|
||||
* @param permissionsPolicyConfig the customization to apply to the header
|
||||
*/
|
||||
fun permissionsPolicy(permissionsPolicyConfig: ServerPermissionsPolicyDsl.() -> Unit) {
|
||||
this.permissionsPolicy = ServerPermissionsPolicyDsl().apply(permissionsPolicyConfig).get()
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables HTTP response headers.
|
||||
*/
|
||||
|
@ -170,6 +186,9 @@ class ServerHeadersDsl {
|
|||
featurePolicyDirectives?.also {
|
||||
headers.featurePolicy(featurePolicyDirectives)
|
||||
}
|
||||
permissionsPolicy?.also {
|
||||
headers.permissionsPolicy(permissionsPolicy)
|
||||
}
|
||||
referrerPolicy?.also {
|
||||
headers.referrerPolicy(referrerPolicy)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright 2002-2020 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.web.server
|
||||
|
||||
import org.springframework.security.web.server.header.ReferrerPolicyServerHttpHeadersWriter
|
||||
|
||||
/**
|
||||
* A Kotlin DSL to configure the [ServerHttpSecurity] permissions policy header using
|
||||
* idiomatic Kotlin code.
|
||||
*
|
||||
* @author Christophe Gilles
|
||||
* @since 5.5
|
||||
* @property policy the policy to be used in the response header.
|
||||
*/
|
||||
@ServerSecurityMarker
|
||||
class ServerPermissionsPolicyDsl {
|
||||
var policy: String? = null
|
||||
|
||||
internal fun get(): (ServerHttpSecurity.HeaderSpec.PermissionsPolicySpec) -> Unit {
|
||||
return { permissionsPolicy ->
|
||||
policy?.also {
|
||||
permissionsPolicy.policy(policy)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -41,6 +41,7 @@ class HeadersDsl {
|
|||
private var contentSecurityPolicy: ((HeadersConfigurer<HttpSecurity>.ContentSecurityPolicyConfig) -> Unit)? = null
|
||||
private var referrerPolicy: ((HeadersConfigurer<HttpSecurity>.ReferrerPolicyConfig) -> Unit)? = null
|
||||
private var featurePolicyDirectives: String? = null
|
||||
private var permissionsPolicy: ((HeadersConfigurer<HttpSecurity>.PermissionsPolicyConfig) -> Unit)? = null
|
||||
private var disabled = false
|
||||
private var headerWriters = mutableListOf<HeaderWriter>()
|
||||
|
||||
|
@ -164,6 +165,21 @@ class HeadersDsl {
|
|||
this.featurePolicyDirectives = policyDirectives
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows configuration for <a href="https://w3c.github.io/webappsec-permissions-policy/">Permissions
|
||||
* Policy</a>.
|
||||
*
|
||||
* <p>
|
||||
* Calling this method automatically enables (includes) the Permissions-Policy
|
||||
* header in the response using the supplied policy directive(s).
|
||||
* <p>
|
||||
*
|
||||
* @param policyDirectives policyDirectives the security policy directive(s)
|
||||
*/
|
||||
fun permissionsPolicy(permissionsPolicyConfig: PermissionsPolicyDsl.() -> Unit) {
|
||||
this.permissionsPolicy = PermissionsPolicyDsl().apply(permissionsPolicyConfig).get()
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a [HeaderWriter] instance.
|
||||
*
|
||||
|
@ -217,6 +233,9 @@ class HeadersDsl {
|
|||
featurePolicyDirectives?.also {
|
||||
headers.featurePolicy(featurePolicyDirectives)
|
||||
}
|
||||
permissionsPolicy?.also {
|
||||
headers.permissionsPolicy(permissionsPolicy)
|
||||
}
|
||||
headerWriters.forEach { headerWriter ->
|
||||
headers.addHeaderWriter(headerWriter)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2002-2020 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.web.servlet.headers
|
||||
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity
|
||||
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer
|
||||
|
||||
/**
|
||||
* A Kotlin DSL to configure the [HttpSecurity] permissions policy header using
|
||||
* idiomatic Kotlin code.
|
||||
*
|
||||
* @author Christophe Gilles
|
||||
* @since 5.5
|
||||
* @property policy the policy to be used in the response header.
|
||||
*/
|
||||
@HeadersSecurityMarker
|
||||
class PermissionsPolicyDsl {
|
||||
var policy: String? = null
|
||||
|
||||
internal fun get(): (HeadersConfigurer<HttpSecurity>.PermissionsPolicyConfig) -> Unit {
|
||||
return { permissionsPolicy ->
|
||||
policy?.also {
|
||||
permissionsPolicy.policy(policy)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -919,7 +919,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? & referrer-policy? & feature-policy? & header*)}
|
||||
element headers { headers-options.attlist, (cache-control? & xss-protection? & hsts? & frame-options? & content-type-options? & hpkp? & content-security-policy? & referrer-policy? & feature-policy? & permissions-policy? & header*)}
|
||||
headers-options.attlist &=
|
||||
## Specifies if the default headers should be disabled. Default false.
|
||||
attribute defaults-disabled {xsd:token}?
|
||||
|
@ -1007,6 +1007,13 @@ feature-options.attlist &=
|
|||
## The security policy directive(s) for the Feature-Policy header.
|
||||
attribute policy-directives {xsd:token}?
|
||||
|
||||
permissions-policy =
|
||||
## Adds support for Permissions Policy
|
||||
element permissions-policy {permissions-options.attlist}
|
||||
permissions-options.attlist &=
|
||||
## The policies for the Permissions-Policy header.
|
||||
attribute policy {xsd:token}?
|
||||
|
||||
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}
|
||||
|
|
|
@ -2692,6 +2692,7 @@
|
|||
<xs:element ref="security:content-security-policy"/>
|
||||
<xs:element ref="security:referrer-policy"/>
|
||||
<xs:element ref="security:feature-policy"/>
|
||||
<xs:element ref="security:permissions-policy"/>
|
||||
<xs:element ref="security:header"/>
|
||||
</xs:choice>
|
||||
<xs:attributeGroup ref="security:headers-options.attlist"/>
|
||||
|
@ -2926,6 +2927,23 @@
|
|||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:attributeGroup>
|
||||
<xs:element name="permissions-policy">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Adds support for Permissions Policy
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
<xs:complexType>
|
||||
<xs:attributeGroup ref="security:permissions-options.attlist"/>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
<xs:attributeGroup name="permissions-options.attlist">
|
||||
<xs:attribute name="policy" type="xs:token">
|
||||
<xs:annotation>
|
||||
<xs:documentation>The policies for the Permissions-Policy header.
|
||||
</xs:documentation>
|
||||
</xs:annotation>
|
||||
</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
|
||||
|
|
|
@ -447,6 +447,44 @@ public class HeadersConfigurerTests {
|
|||
.withRootCauseInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWhenPermissionsPolicyConfiguredThenPermissionsPolicyHeaderInResponse() throws Exception {
|
||||
this.spring.register(PermissionsPolicyConfig.class).autowire();
|
||||
ResultMatcher permissionsPolicy = header().string("Permissions-Policy", "geolocation=(self)");
|
||||
// @formatter:off
|
||||
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
|
||||
.andExpect(permissionsPolicy)
|
||||
.andReturn();
|
||||
// @formatter:on
|
||||
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Permissions-Policy");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWhenPermissionsPolicyConfiguredWithStringThenPermissionsPolicyHeaderInResponse() throws Exception {
|
||||
this.spring.register(PermissionsPolicyStringConfig.class).autowire();
|
||||
ResultMatcher permissionsPolicy = header().string("Permissions-Policy", "geolocation=(self)");
|
||||
// @formatter:off
|
||||
MvcResult mvcResult = this.mvc.perform(get("/").secure(true))
|
||||
.andExpect(permissionsPolicy)
|
||||
.andReturn();
|
||||
// @formatter:on
|
||||
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly("Permissions-Policy");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWhenPermissionsPolicyEmptyThenException() {
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(() -> this.spring.register(PermissionsPolicyInvalidConfig.class).autowire())
|
||||
.withRootCauseInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void configureWhenPermissionsPolicyStringEmptyThenException() {
|
||||
assertThatExceptionOfType(BeanCreationException.class)
|
||||
.isThrownBy(() -> this.spring.register(PermissionsPolicyInvalidStringConfig.class).autowire())
|
||||
.withRootCauseInstanceOf(IllegalArgumentException.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getWhenHstsConfiguredWithPreloadThenStrictTransportSecurityHeaderWithPreloadInResponse()
|
||||
throws Exception {
|
||||
|
@ -1012,6 +1050,68 @@ public class HeadersConfigurerTests {
|
|||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class PermissionsPolicyConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.permissionsPolicy((permissionsPolicy) -> permissionsPolicy.policy("geolocation=(self)"));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class PermissionsPolicyStringConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.permissionsPolicy()
|
||||
.policy("geolocation=(self)");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class PermissionsPolicyInvalidConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.permissionsPolicy((permissionsPolicy) -> permissionsPolicy.policy(null));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class PermissionsPolicyInvalidStringConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// @formatter:off
|
||||
http
|
||||
.headers()
|
||||
.defaultsDisabled()
|
||||
.permissionsPolicy()
|
||||
.policy("");
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class HstsWithPreloadConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
|
|
|
@ -332,6 +332,17 @@ public class HttpHeadersConfigTests {
|
|||
() -> this.spring.configLocations(this.xml("DefaultsDisabledWithOnlyHeaderValue")).autowire());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenPermissionsPolicyConfiguredWithGeolocationSelfThenGeolocationSelf() throws Exception {
|
||||
this.spring.configLocations(this.xml("DefaultsDisabledWithPermissionsPolicy")).autowire();
|
||||
// @formatter:off
|
||||
this.mvc.perform(get("/"))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(excludesDefaults())
|
||||
.andExpect(header().string("Permissions-Policy", "geolocation=(self)"));
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
@Test
|
||||
public void requestWhenUsingXssProtectionThenDefaultsToModeBlock() throws Exception {
|
||||
Set<String> excludedHeaders = new HashSet<>(defaultHeaders.keySet());
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* Copyright 2002-2020 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.web.server
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.context.annotation.Bean
|
||||
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
|
||||
import org.springframework.security.config.test.SpringTestRule
|
||||
import org.springframework.security.web.server.SecurityWebFilterChain
|
||||
import org.springframework.test.web.reactive.server.WebTestClient
|
||||
import org.springframework.web.reactive.config.EnableWebFlux
|
||||
|
||||
/**
|
||||
* Tests for [ServerPermissionsPolicyDsl]
|
||||
*
|
||||
* @author Christophe Gilles
|
||||
*/
|
||||
class ServerPermissionsPolicyDslTests {
|
||||
@Rule
|
||||
@JvmField
|
||||
val spring = SpringTestRule()
|
||||
|
||||
private lateinit var client: WebTestClient
|
||||
|
||||
@Autowired
|
||||
fun setup(context: ApplicationContext) {
|
||||
this.client = WebTestClient
|
||||
.bindToApplicationContext(context)
|
||||
.configureClient()
|
||||
.build()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when permissions policy configured then permissions policy header in response`() {
|
||||
this.spring.register(PermissionsPolicyConfig::class.java).autowire()
|
||||
|
||||
this.client.get()
|
||||
.uri("/")
|
||||
.exchange()
|
||||
.expectHeader().doesNotExist("Permissions-Policy")
|
||||
}
|
||||
|
||||
@EnableWebFluxSecurity
|
||||
@EnableWebFlux
|
||||
open class PermissionsPolicyConfig {
|
||||
@Bean
|
||||
open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
|
||||
return http {
|
||||
headers {
|
||||
permissionsPolicy { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when custom policy configured then custom policy in response header`() {
|
||||
this.spring.register(CustomPolicyConfig::class.java).autowire()
|
||||
|
||||
this.client.get()
|
||||
.uri("/")
|
||||
.exchange()
|
||||
.expectHeader().valueEquals("Permissions-Policy", "geolocation=(self)")
|
||||
}
|
||||
|
||||
@EnableWebFluxSecurity
|
||||
@EnableWebFlux
|
||||
open class CustomPolicyConfig {
|
||||
@Bean
|
||||
open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
|
||||
return http {
|
||||
headers {
|
||||
permissionsPolicy {
|
||||
policy = "geolocation=(self)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -24,6 +24,7 @@ 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.config.web.servlet.headers.PermissionsPolicyDsl
|
||||
import org.springframework.security.web.header.writers.StaticHeadersWriter
|
||||
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter
|
||||
import org.springframework.security.web.server.header.ContentTypeOptionsServerHttpHeadersWriter
|
||||
|
@ -93,6 +94,29 @@ class HeadersDslTests {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `headers when permissions policy configured then header in response`() {
|
||||
this.spring.register(PermissionsPolicyConfig::class.java).autowire()
|
||||
|
||||
this.mockMvc.get("/")
|
||||
.andExpect {
|
||||
header { string("Permissions-Policy", "geolocation=(self)") }
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
open class PermissionsPolicyConfig : WebSecurityConfigurerAdapter() {
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
headers {
|
||||
permissionsPolicy {
|
||||
policy = "geolocation=(self)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `request when headers disabled then no security headers are in the response`() {
|
||||
this.spring.register(HeadersDisabledConfig::class.java).autowire()
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
~ Copyright 2002-2020 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.
|
||||
-->
|
||||
|
||||
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://www.springframework.org/schema/security"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/security
|
||||
https://www.springframework.org/schema/security/spring-security.xsd
|
||||
http://www.springframework.org/schema/beans
|
||||
https://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<http auto-config="true">
|
||||
<headers defaults-disabled="true">
|
||||
<permissions-policy policy="geolocation=(self)"/>
|
||||
</headers>
|
||||
</http>
|
||||
|
||||
<b:bean name="simple" class="org.springframework.security.config.http.HttpHeadersConfigTests.SimpleController"/>
|
||||
|
||||
<b:import resource="userservice.xml"/>
|
||||
</b:beans>
|
|
@ -339,6 +339,28 @@ With Feature Policy, developers can opt-in to a set of "policies" for the browse
|
|||
These policies restrict what APIs the site can access or modify the browser's default behavior for certain features.
|
||||
|
||||
|
||||
[[headers-permissions]]
|
||||
== Permissions Policy
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Refer to the relevant sections to see how to configure both <<servlet-headers-permissions,servlet>> and <<webflux-headers-permissions,webflux>> based applications.
|
||||
====
|
||||
|
||||
https://w3c.github.io/webappsec-permissions-policy/[Permissions Policy] is a mechanism that allows web developers to selectively enable, disable, and modify the behavior of certain APIs and web features in the browser.
|
||||
|
||||
.Permissions Policy Example
|
||||
====
|
||||
[source]
|
||||
----
|
||||
Permissions-Policy: geolocation=(self)
|
||||
----
|
||||
====
|
||||
|
||||
With Permissions Policy, developers can opt-in to a set of "policies" for the browser to enforce on specific features used throughout your site.
|
||||
These policies restrict what APIs the site can access or modify the browser's default behavior for certain features.
|
||||
|
||||
|
||||
[[headers-clear-site-data]]
|
||||
== Clear Site Data
|
||||
|
||||
|
|
|
@ -472,6 +472,58 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
|
|||
====
|
||||
|
||||
|
||||
[[webflux-headers-permissions]]
|
||||
== Permissions Policy
|
||||
|
||||
Spring Security does not add <<headers-permissions,Permissions Policy>> headers by default.
|
||||
The following `Permissions-Policy` header:
|
||||
|
||||
.Permissions-Policy Example
|
||||
====
|
||||
[source]
|
||||
----
|
||||
Permissions-Policy: geolocation=(self)
|
||||
----
|
||||
====
|
||||
|
||||
You can enable the Permissions Policy header as shown below:
|
||||
|
||||
.Permissions-Policy Configuration
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
|
||||
http
|
||||
// ...
|
||||
.headers(headers -> headers
|
||||
.permissionsPolicy(permissions -> permissions
|
||||
.policy("geolocation=(self)")
|
||||
)
|
||||
);
|
||||
return http.build();
|
||||
}
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Bean
|
||||
fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
|
||||
return http {
|
||||
// ...
|
||||
headers {
|
||||
permissionsPolicy {
|
||||
policy = "geolocation=(self)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
|
||||
[[webflux-headers-clear-site-data]]
|
||||
== Clear Site Data
|
||||
|
||||
|
|
|
@ -816,6 +816,76 @@ class SecurityConfig : WebSecurityConfigurerAdapter() {
|
|||
----
|
||||
====
|
||||
|
||||
[[servlet-headers-permissions]]
|
||||
== Permissions Policy
|
||||
|
||||
Spring Security does not add <<headers-permissions,Permissions Policy>> headers by default.
|
||||
The following `Permissions-Policy` header:
|
||||
|
||||
.Permissions-Policy Example
|
||||
====
|
||||
[source]
|
||||
----
|
||||
Permissions-Policy: geolocation=(self)
|
||||
----
|
||||
====
|
||||
|
||||
can enable the Permissions Policy header using the configuration shown below:
|
||||
|
||||
.Permissions-Policy
|
||||
====
|
||||
.Java
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@EnableWebSecurity
|
||||
public class WebSecurityConfig extends
|
||||
WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
// ...
|
||||
.headers(headers -> headers
|
||||
.permissionsPolicy(permissions -> permissions
|
||||
.policy("geolocation=(self)")
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
.XML
|
||||
[source,xml,role="secondary"]
|
||||
----
|
||||
<http>
|
||||
<!-- ... -->
|
||||
|
||||
<headers>
|
||||
<permissions-policy policy="geolocation=(self)" />
|
||||
</headers>
|
||||
</http>
|
||||
----
|
||||
|
||||
.Kotlin
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@EnableWebSecurity
|
||||
class SecurityConfig : WebSecurityConfigurerAdapter() {
|
||||
|
||||
override fun configure(http: HttpSecurity) {
|
||||
http {
|
||||
// ...
|
||||
headers {
|
||||
permissionPolicy {
|
||||
policy = "geolocation=(self)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
[[servlet-headers-clear-site-data]]
|
||||
== Clear Site Data
|
||||
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright 2002-2020 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.web.header.writers;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.springframework.security.web.header.HeaderWriter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Provides support for
|
||||
* <a href="https://w3c.github.io/webappsec-permissions-policy//">Permisisons Policy</a>.
|
||||
* <p>
|
||||
* Permissions Policy allows web developers to selectively enable, disable, and modify the
|
||||
* behavior of certain APIs and web features in the browser.
|
||||
* <p>
|
||||
* A declaration of a permissions policy contains a set of security policies, each
|
||||
* responsible for declaring the restrictions for a particular feature type.
|
||||
*
|
||||
* @author Christophe Gilles
|
||||
* @since 5.5
|
||||
*/
|
||||
public final class PermissionsPolicyHeaderWriter implements HeaderWriter {
|
||||
|
||||
private static final String PERMISSIONS_POLICY_HEADER = "Permissions-Policy";
|
||||
|
||||
private String policy;
|
||||
|
||||
/**
|
||||
* Create a new instance of {@link PermissionsPolicyHeaderWriter}.
|
||||
*/
|
||||
public PermissionsPolicyHeaderWriter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of {@link PermissionsPolicyHeaderWriter} with supplied
|
||||
* security policy.
|
||||
* @param policy the security policy
|
||||
* @throws IllegalArgumentException if policy is {@code null} or empty
|
||||
*/
|
||||
public PermissionsPolicyHeaderWriter(String policy) {
|
||||
setPolicy(policy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the policy to be used in the response header.
|
||||
* @param policy a permissions policy
|
||||
* @throws IllegalArgumentException if policy is null
|
||||
*/
|
||||
public void setPolicy(String policy) {
|
||||
Assert.hasLength(policy, "policy can not be null or empty");
|
||||
this.policy = policy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeHeaders(HttpServletRequest request, HttpServletResponse response) {
|
||||
if (!response.containsHeader(PERMISSIONS_POLICY_HEADER)) {
|
||||
response.setHeader(PERMISSIONS_POLICY_HEADER, this.policy);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + " [policy=" + this.policy + "]";
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright 2002-2020 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.web.server.header;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.security.web.server.header.StaticServerHttpHeadersWriter.Builder;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
/**
|
||||
* Writes the {@code Permissions-Policy} response header with configured policy
|
||||
* directives.
|
||||
*
|
||||
* @author Christophe Gilles
|
||||
* @since 5.5
|
||||
*/
|
||||
public final class PermissionsPolicyServerHttpHeadersWriter implements ServerHttpHeadersWriter {
|
||||
|
||||
public static final String PERMISSIONS_POLICY = "Permissions-Policy";
|
||||
|
||||
private ServerHttpHeadersWriter delegate;
|
||||
|
||||
@Override
|
||||
public Mono<Void> writeHttpHeaders(ServerWebExchange exchange) {
|
||||
return (this.delegate != null) ? this.delegate.writeHttpHeaders(exchange) : Mono.empty();
|
||||
}
|
||||
|
||||
private static ServerHttpHeadersWriter createDelegate(String policyDirectives) {
|
||||
Builder builder = StaticServerHttpHeadersWriter.builder();
|
||||
builder.header(PERMISSIONS_POLICY, policyDirectives);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the policy to be used in the response header.
|
||||
* @param policy the policy
|
||||
* @throws IllegalArgumentException if policy is {@code null}
|
||||
*/
|
||||
public void setPolicy(String policy) {
|
||||
Assert.notNull(policy, "policy must not be null");
|
||||
this.delegate = createDelegate(policy);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright 2002-2020 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.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.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests for {@link PermissionsPolicyHeaderWriter}.
|
||||
*
|
||||
* @author Christophe Gilles
|
||||
*/
|
||||
public class PermissionsPolicyHeaderWriterTests {
|
||||
|
||||
private static final String DEFAULT_POLICY_DIRECTIVES = "geolocation=(self)";
|
||||
|
||||
private MockHttpServletRequest request;
|
||||
|
||||
private MockHttpServletResponse response;
|
||||
|
||||
private PermissionsPolicyHeaderWriter writer;
|
||||
|
||||
private static final String PERMISSIONS_POLICY_HEADER = "Permissions-Policy";
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.request = new MockHttpServletRequest();
|
||||
this.response = new MockHttpServletResponse();
|
||||
this.writer = new PermissionsPolicyHeaderWriter(DEFAULT_POLICY_DIRECTIVES);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeHeadersPermissionsPolicyDefault() {
|
||||
this.writer.writeHeaders(this.request, this.response);
|
||||
assertThat(this.response.getHeaderNames()).hasSize(1);
|
||||
assertThat(this.response.getHeader("Permissions-Policy")).isEqualTo(DEFAULT_POLICY_DIRECTIVES);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWriterWithNullPolicyShouldThrowException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new PermissionsPolicyHeaderWriter(null))
|
||||
.withMessage("policy can not be null or empty");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWriterWithEmptyPolicyShouldThrowException() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new PermissionsPolicyHeaderWriter(""))
|
||||
.withMessage("policy can not be null or empty");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeHeaderOnlyIfNotPresent() {
|
||||
String value = new String("value");
|
||||
this.response.setHeader(PERMISSIONS_POLICY_HEADER, value);
|
||||
this.writer.writeHeaders(this.request, this.response);
|
||||
assertThat(this.response.getHeader(PERMISSIONS_POLICY_HEADER)).isSameAs(value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright 2002-2020 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.web.server.header;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
|
||||
import org.springframework.mock.web.server.MockServerWebExchange;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link PermissionsPolicyServerHttpHeadersWriter}.
|
||||
*
|
||||
* @author Christophe Gilles
|
||||
*/
|
||||
public class PermissionsPolicyServerHttpHeadersWriterTests {
|
||||
|
||||
private static final String DEFAULT_POLICY_DIRECTIVES = "geolocation=(self)";
|
||||
|
||||
private ServerWebExchange exchange;
|
||||
|
||||
private PermissionsPolicyServerHttpHeadersWriter writer;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
this.exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/"));
|
||||
this.writer = new PermissionsPolicyServerHttpHeadersWriter();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeHeadersWhenUsingDefaultsThenDoesNotWrite() {
|
||||
this.writer.writeHttpHeaders(this.exchange);
|
||||
HttpHeaders headers = this.exchange.getResponse().getHeaders();
|
||||
assertThat(headers).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeHeadersWhenUsingPolicyThenWritesPolicy() {
|
||||
this.writer.setPolicy(DEFAULT_POLICY_DIRECTIVES);
|
||||
this.writer.writeHttpHeaders(this.exchange);
|
||||
HttpHeaders headers = this.exchange.getResponse().getHeaders();
|
||||
assertThat(headers).hasSize(1);
|
||||
assertThat(headers.get(PermissionsPolicyServerHttpHeadersWriter.PERMISSIONS_POLICY))
|
||||
.containsOnly(DEFAULT_POLICY_DIRECTIVES);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeHeadersWhenAlreadyWrittenThenWritesHeader() {
|
||||
this.writer.setPolicy(DEFAULT_POLICY_DIRECTIVES);
|
||||
String headerValue = "camera=(self)";
|
||||
this.exchange.getResponse().getHeaders().set(PermissionsPolicyServerHttpHeadersWriter.PERMISSIONS_POLICY,
|
||||
headerValue);
|
||||
this.writer.writeHttpHeaders(this.exchange);
|
||||
HttpHeaders headers = this.exchange.getResponse().getHeaders();
|
||||
assertThat(headers).hasSize(1);
|
||||
assertThat(headers.get(PermissionsPolicyServerHttpHeadersWriter.PERMISSIONS_POLICY)).containsOnly(headerValue);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue