Add Cross Origin Policies headers

Add DSL support for Cross-Origin-Opener-Policy, Cross-Origin-Embedder-Policy and Cross-Origin-Resource-Policy headers

Closes gh-9385, gh-10118
This commit is contained in:
Marcus Da Coregio 2021-12-03 16:47:21 -03:00 committed by Eleftheria Stein-Kousathana
parent 7ec3b55ab3
commit 65426a40ec
38 changed files with 2513 additions and 9 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 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.
@ -31,6 +31,9 @@ import org.springframework.security.web.header.HeaderWriter;
import org.springframework.security.web.header.HeaderWriterFilter;
import org.springframework.security.web.header.writers.CacheControlHeadersWriter;
import org.springframework.security.web.header.writers.ContentSecurityPolicyHeaderWriter;
import org.springframework.security.web.header.writers.CrossOriginEmbedderPolicyHeaderWriter;
import org.springframework.security.web.header.writers.CrossOriginOpenerPolicyHeaderWriter;
import org.springframework.security.web.header.writers.CrossOriginResourcePolicyHeaderWriter;
import org.springframework.security.web.header.writers.FeaturePolicyHeaderWriter;
import org.springframework.security.web.header.writers.HpkpHeaderWriter;
import org.springframework.security.web.header.writers.HstsHeaderWriter;
@ -97,6 +100,12 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
private final PermissionsPolicyConfig permissionsPolicy = new PermissionsPolicyConfig();
private final CrossOriginOpenerPolicyConfig crossOriginOpenerPolicy = new CrossOriginOpenerPolicyConfig();
private final CrossOriginEmbedderPolicyConfig crossOriginEmbedderPolicy = new CrossOriginEmbedderPolicyConfig();
private final CrossOriginResourcePolicyConfig crossOriginResourcePolicy = new CrossOriginResourcePolicyConfig();
/**
* Creates a new instance
*
@ -392,6 +401,9 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
addIfNotNull(writers, this.referrerPolicy.writer);
addIfNotNull(writers, this.featurePolicy.writer);
addIfNotNull(writers, this.permissionsPolicy.writer);
addIfNotNull(writers, this.crossOriginOpenerPolicy.writer);
addIfNotNull(writers, this.crossOriginEmbedderPolicy.writer);
addIfNotNull(writers, this.crossOriginResourcePolicy.writer);
writers.addAll(this.headerWriters);
return writers;
}
@ -544,6 +556,129 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
return this.permissionsPolicy;
}
/**
* Allows configuration for <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
* Cross-Origin-Opener-Policy</a> header.
* <p>
* Configuration is provided to the {@link CrossOriginOpenerPolicyHeaderWriter} which
* responsible for writing the header.
* </p>
* @return the {@link CrossOriginOpenerPolicyConfig} for additional confniguration
* @since 5.7
* @see CrossOriginOpenerPolicyHeaderWriter
*/
public CrossOriginOpenerPolicyConfig crossOriginOpenerPolicy() {
this.crossOriginOpenerPolicy.writer = new CrossOriginOpenerPolicyHeaderWriter();
return this.crossOriginOpenerPolicy;
}
/**
* Allows configuration for <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
* Cross-Origin-Opener-Policy</a> header.
* <p>
* Calling this method automatically enables (includes) the
* {@code Cross-Origin-Opener-Policy} header in the response using the supplied
* policy.
* <p>
* <p>
* Configuration is provided to the {@link CrossOriginOpenerPolicyHeaderWriter} which
* responsible for writing the header.
* </p>
* @return the {@link HeadersConfigurer} for additional customizations
* @since 5.7
* @see CrossOriginOpenerPolicyHeaderWriter
*/
public HeadersConfigurer<H> crossOriginOpenerPolicy(
Customizer<CrossOriginOpenerPolicyConfig> crossOriginOpenerPolicyCustomizer) {
this.crossOriginOpenerPolicy.writer = new CrossOriginOpenerPolicyHeaderWriter();
crossOriginOpenerPolicyCustomizer.customize(this.crossOriginOpenerPolicy);
return HeadersConfigurer.this;
}
/**
* Allows configuration for <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
* Cross-Origin-Embedder-Policy</a> header.
* <p>
* Configuration is provided to the {@link CrossOriginEmbedderPolicyHeaderWriter}
* which is responsible for writing the header.
* </p>
* @return the {@link CrossOriginEmbedderPolicyConfig} for additional customizations
* @since 5.7
* @see CrossOriginEmbedderPolicyHeaderWriter
*/
public CrossOriginEmbedderPolicyConfig crossOriginEmbedderPolicy() {
this.crossOriginEmbedderPolicy.writer = new CrossOriginEmbedderPolicyHeaderWriter();
return this.crossOriginEmbedderPolicy;
}
/**
* Allows configuration for <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
* Cross-Origin-Embedder-Policy</a> header.
* <p>
* Calling this method automatically enables (includes) the
* {@code Cross-Origin-Embedder-Policy} header in the response using the supplied
* policy.
* <p>
* <p>
* Configuration is provided to the {@link CrossOriginEmbedderPolicyHeaderWriter}
* which is responsible for writing the header.
* </p>
* @return the {@link HeadersConfigurer} for additional customizations
* @since 5.7
* @see CrossOriginEmbedderPolicyHeaderWriter
*/
public HeadersConfigurer<H> crossOriginEmbedderPolicy(
Customizer<CrossOriginEmbedderPolicyConfig> crossOriginEmbedderPolicyCustomizer) {
this.crossOriginEmbedderPolicy.writer = new CrossOriginEmbedderPolicyHeaderWriter();
crossOriginEmbedderPolicyCustomizer.customize(this.crossOriginEmbedderPolicy);
return HeadersConfigurer.this;
}
/**
* Allows configuration for <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
* Cross-Origin-Resource-Policy</a> header.
* <p>
* Configuration is provided to the {@link CrossOriginResourcePolicyHeaderWriter}
* which is responsible for writing the header:
* </p>
* @return the {@link HeadersConfigurer} for additional customizations
* @since 5.7
* @see CrossOriginResourcePolicyHeaderWriter
*/
public CrossOriginResourcePolicyConfig crossOriginResourcePolicy() {
this.crossOriginResourcePolicy.writer = new CrossOriginResourcePolicyHeaderWriter();
return this.crossOriginResourcePolicy;
}
/**
* Allows configuration for <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
* Cross-Origin-Resource-Policy</a> header.
* <p>
* Calling this method automatically enables (includes) the
* {@code Cross-Origin-Resource-Policy} header in the response using the supplied
* policy.
* <p>
* <p>
* Configuration is provided to the {@link CrossOriginResourcePolicyHeaderWriter}
* which is responsible for writing the header:
* </p>
* @return the {@link HeadersConfigurer} for additional customizations
* @since 5.7
* @see CrossOriginResourcePolicyHeaderWriter
*/
public HeadersConfigurer<H> crossOriginResourcePolicy(
Customizer<CrossOriginResourcePolicyConfig> crossOriginResourcePolicyCustomizer) {
this.crossOriginResourcePolicy.writer = new CrossOriginResourcePolicyHeaderWriter();
crossOriginResourcePolicyCustomizer.customize(this.crossOriginResourcePolicy);
return HeadersConfigurer.this;
}
public final class ContentTypeOptionsConfig {
private XContentTypeOptionsHeaderWriter writer;
@ -1142,4 +1277,96 @@ public class HeadersConfigurer<H extends HttpSecurityBuilder<H>>
}
public final class CrossOriginOpenerPolicyConfig {
private CrossOriginOpenerPolicyHeaderWriter writer;
public CrossOriginOpenerPolicyConfig() {
}
/**
* Sets the policy to be used in the {@code Cross-Origin-Opener-Policy} header
* @param openerPolicy a {@code Cross-Origin-Opener-Policy}
* @return the {@link CrossOriginOpenerPolicyConfig} for additional configuration
* @throws IllegalArgumentException if openerPolicy is null
*/
public CrossOriginOpenerPolicyConfig policy(
CrossOriginOpenerPolicyHeaderWriter.CrossOriginOpenerPolicy openerPolicy) {
this.writer.setPolicy(openerPolicy);
return this;
}
/**
* Allows completing configuration of Cross Origin Opener Policy and continuing
* configuration of headers.
* @return the {@link HeadersConfigurer} for additional configuration
*/
public HeadersConfigurer<H> and() {
return HeadersConfigurer.this;
}
}
public final class CrossOriginEmbedderPolicyConfig {
private CrossOriginEmbedderPolicyHeaderWriter writer;
public CrossOriginEmbedderPolicyConfig() {
}
/**
* Sets the policy to be used in the {@code Cross-Origin-Embedder-Policy} header
* @param embedderPolicy a {@code Cross-Origin-Embedder-Policy}
* @return the {@link CrossOriginEmbedderPolicyConfig} for additional
* configuration
* @throws IllegalArgumentException if embedderPolicy is null
*/
public CrossOriginEmbedderPolicyConfig policy(
CrossOriginEmbedderPolicyHeaderWriter.CrossOriginEmbedderPolicy embedderPolicy) {
this.writer.setPolicy(embedderPolicy);
return this;
}
/**
* Allows completing configuration of Cross-Origin-Embedder-Policy and continuing
* configuration of headers.
* @return the {@link HeadersConfigurer} for additional configuration
*/
public HeadersConfigurer<H> and() {
return HeadersConfigurer.this;
}
}
public final class CrossOriginResourcePolicyConfig {
private CrossOriginResourcePolicyHeaderWriter writer;
public CrossOriginResourcePolicyConfig() {
}
/**
* Sets the policy to be used in the {@code Cross-Origin-Resource-Policy} header
* @param resourcePolicy a {@code Cross-Origin-Resource-Policy}
* @return the {@link CrossOriginResourcePolicyConfig} for additional
* configuration
* @throws IllegalArgumentException if resourcePolicy is null
*/
public CrossOriginResourcePolicyConfig policy(
CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy resourcePolicy) {
this.writer.setPolicy(resourcePolicy);
return this;
}
/**
* Allows completing configuration of Cross-Origin-Resource-Policy and continuing
* configuration of headers.
* @return the {@link HeadersConfigurer} for additional configuration
*/
public HeadersConfigurer<H> and() {
return HeadersConfigurer.this;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 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.
@ -36,6 +36,9 @@ import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.security.web.header.HeaderWriterFilter;
import org.springframework.security.web.header.writers.CacheControlHeadersWriter;
import org.springframework.security.web.header.writers.ContentSecurityPolicyHeaderWriter;
import org.springframework.security.web.header.writers.CrossOriginEmbedderPolicyHeaderWriter;
import org.springframework.security.web.header.writers.CrossOriginOpenerPolicyHeaderWriter;
import org.springframework.security.web.header.writers.CrossOriginResourcePolicyHeaderWriter;
import org.springframework.security.web.header.writers.FeaturePolicyHeaderWriter;
import org.springframework.security.web.header.writers.HpkpHeaderWriter;
import org.springframework.security.web.header.writers.HstsHeaderWriter;
@ -122,6 +125,12 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
private static final String PERMISSIONS_POLICY_ELEMENT = "permissions-policy";
private static final String CROSS_ORIGIN_OPENER_POLICY_ELEMENT = "cross-origin-opener-policy";
private static final String CROSS_ORIGIN_EMBEDDER_POLICY_ELEMENT = "cross-origin-embedder-policy";
private static final String CROSS_ORIGIN_RESOURCE_POLICY_ELEMENT = "cross-origin-resource-policy";
private static final String ALLOW_FROM = "ALLOW-FROM";
private ManagedList<BeanMetadataElement> headerWriters;
@ -144,6 +153,9 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
parseReferrerPolicyElement(element, parserContext);
parseFeaturePolicyElement(element, parserContext);
parsePermissionsPolicyElement(element, parserContext);
parseCrossOriginOpenerPolicy(disabled, element);
parseCrossOriginEmbedderPolicy(disabled, element);
parseCrossOriginResourcePolicy(disabled, element);
parseHeaderElements(element);
boolean noWriters = this.headerWriters.isEmpty();
if (disabled && !noWriters) {
@ -376,6 +388,75 @@ public class HeadersBeanDefinitionParser implements BeanDefinitionParser {
this.headerWriters.add(headersWriter.getBeanDefinition());
}
private void parseCrossOriginOpenerPolicy(boolean elementDisabled, Element element) {
if (elementDisabled || element == null) {
return;
}
CrossOriginOpenerPolicyHeaderWriter writer = new CrossOriginOpenerPolicyHeaderWriter();
Element crossOriginOpenerPolicyElement = DomUtils.getChildElementByTagName(element,
CROSS_ORIGIN_OPENER_POLICY_ELEMENT);
if (crossOriginOpenerPolicyElement != null) {
addCrossOriginOpenerPolicy(crossOriginOpenerPolicyElement, writer);
}
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(CrossOriginOpenerPolicyHeaderWriter.class, () -> writer);
this.headerWriters.add(builder.getBeanDefinition());
}
private void parseCrossOriginEmbedderPolicy(boolean elementDisabled, Element element) {
if (elementDisabled || element == null) {
return;
}
CrossOriginEmbedderPolicyHeaderWriter writer = new CrossOriginEmbedderPolicyHeaderWriter();
Element crossOriginEmbedderPolicyElement = DomUtils.getChildElementByTagName(element,
CROSS_ORIGIN_EMBEDDER_POLICY_ELEMENT);
if (crossOriginEmbedderPolicyElement != null) {
addCrossOriginEmbedderPolicy(crossOriginEmbedderPolicyElement, writer);
}
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(CrossOriginEmbedderPolicyHeaderWriter.class, () -> writer);
this.headerWriters.add(builder.getBeanDefinition());
}
private void parseCrossOriginResourcePolicy(boolean elementDisabled, Element element) {
if (elementDisabled || element == null) {
return;
}
CrossOriginResourcePolicyHeaderWriter writer = new CrossOriginResourcePolicyHeaderWriter();
Element crossOriginResourcePolicyElement = DomUtils.getChildElementByTagName(element,
CROSS_ORIGIN_RESOURCE_POLICY_ELEMENT);
if (crossOriginResourcePolicyElement != null) {
addCrossOriginResourcePolicy(crossOriginResourcePolicyElement, writer);
}
BeanDefinitionBuilder builder = BeanDefinitionBuilder
.genericBeanDefinition(CrossOriginResourcePolicyHeaderWriter.class, () -> writer);
this.headerWriters.add(builder.getBeanDefinition());
}
private void addCrossOriginResourcePolicy(Element crossOriginResourcePolicyElement,
CrossOriginResourcePolicyHeaderWriter writer) {
String policy = crossOriginResourcePolicyElement.getAttribute(ATT_POLICY);
if (StringUtils.hasText(policy)) {
writer.setPolicy(CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy.from(policy));
}
}
private void addCrossOriginEmbedderPolicy(Element crossOriginEmbedderPolicyElement,
CrossOriginEmbedderPolicyHeaderWriter writer) {
String policy = crossOriginEmbedderPolicyElement.getAttribute(ATT_POLICY);
if (StringUtils.hasText(policy)) {
writer.setPolicy(CrossOriginEmbedderPolicyHeaderWriter.CrossOriginEmbedderPolicy.from(policy));
}
}
private void addCrossOriginOpenerPolicy(Element crossOriginOpenerPolicyElement,
CrossOriginOpenerPolicyHeaderWriter writer) {
String policy = crossOriginOpenerPolicyElement.getAttribute(ATT_POLICY);
if (StringUtils.hasText(policy)) {
writer.setPolicy(CrossOriginOpenerPolicyHeaderWriter.CrossOriginOpenerPolicy.from(policy));
}
}
private void attrNotAllowed(ParserContext context, String attrName, String otherAttrName, Element element) {
context.getReaderContext().error("Only one of '" + attrName + "' or '" + otherAttrName + "' can be set.",
element);

View File

@ -149,6 +149,12 @@ import org.springframework.security.web.server.header.CacheControlServerHttpHead
import org.springframework.security.web.server.header.CompositeServerHttpHeadersWriter;
import org.springframework.security.web.server.header.ContentSecurityPolicyServerHttpHeadersWriter;
import org.springframework.security.web.server.header.ContentTypeOptionsServerHttpHeadersWriter;
import org.springframework.security.web.server.header.CrossOriginEmbedderPolicyServerHttpHeadersWriter;
import org.springframework.security.web.server.header.CrossOriginEmbedderPolicyServerHttpHeadersWriter.CrossOriginEmbedderPolicy;
import org.springframework.security.web.server.header.CrossOriginOpenerPolicyServerHttpHeadersWriter;
import org.springframework.security.web.server.header.CrossOriginOpenerPolicyServerHttpHeadersWriter.CrossOriginOpenerPolicy;
import org.springframework.security.web.server.header.CrossOriginResourcePolicyServerHttpHeadersWriter;
import org.springframework.security.web.server.header.CrossOriginResourcePolicyServerHttpHeadersWriter.CrossOriginResourcePolicy;
import org.springframework.security.web.server.header.FeaturePolicyServerHttpHeadersWriter;
import org.springframework.security.web.server.header.HttpHeaderWriterWebFilter;
import org.springframework.security.web.server.header.PermissionsPolicyServerHttpHeadersWriter;
@ -2380,10 +2386,17 @@ public class ServerHttpSecurity {
private ReferrerPolicyServerHttpHeadersWriter referrerPolicy = new ReferrerPolicyServerHttpHeadersWriter();
private CrossOriginOpenerPolicyServerHttpHeadersWriter crossOriginOpenerPolicy = new CrossOriginOpenerPolicyServerHttpHeadersWriter();
private CrossOriginEmbedderPolicyServerHttpHeadersWriter crossOriginEmbedderPolicy = new CrossOriginEmbedderPolicyServerHttpHeadersWriter();
private CrossOriginResourcePolicyServerHttpHeadersWriter crossOriginResourcePolicy = new CrossOriginResourcePolicyServerHttpHeadersWriter();
private HeaderSpec() {
this.writers = new ArrayList<>(Arrays.asList(this.cacheControl, this.contentTypeOptions, this.hsts,
this.frameOptions, this.xss, this.featurePolicy, this.permissionsPolicy, this.contentSecurityPolicy,
this.referrerPolicy));
this.referrerPolicy, this.crossOriginOpenerPolicy, this.crossOriginEmbedderPolicy,
this.crossOriginResourcePolicy));
}
/**
@ -2595,6 +2608,84 @@ public class ServerHttpSecurity {
return this;
}
/**
* Configures the <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
* Cross-Origin-Opener-Policy</a> header.
* @return the {@link CrossOriginOpenerPolicySpec} to configure
* @since 5.7
* @see CrossOriginOpenerPolicyServerHttpHeadersWriter
*/
public CrossOriginOpenerPolicySpec crossOriginOpenerPolicy() {
return new CrossOriginOpenerPolicySpec();
}
/**
* Configures the <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
* Cross-Origin-Opener-Policy</a> header.
* @return the {@link HeaderSpec} to customize
* @since 5.7
* @see CrossOriginOpenerPolicyServerHttpHeadersWriter
*/
public HeaderSpec crossOriginOpenerPolicy(
Customizer<CrossOriginOpenerPolicySpec> crossOriginOpenerPolicyCustomizer) {
crossOriginOpenerPolicyCustomizer.customize(new CrossOriginOpenerPolicySpec());
return this;
}
/**
* Configures the <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
* Cross-Origin-Embedder-Policy</a> header.
* @return the {@link CrossOriginEmbedderPolicySpec} to configure
* @since 5.7
* @see CrossOriginEmbedderPolicyServerHttpHeadersWriter
*/
public CrossOriginEmbedderPolicySpec crossOriginEmbedderPolicy() {
return new CrossOriginEmbedderPolicySpec();
}
/**
* Configures the <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
* Cross-Origin-Embedder-Policy</a> header.
* @return the {@link HeaderSpec} to customize
* @since 5.7
* @see CrossOriginEmbedderPolicyServerHttpHeadersWriter
*/
public HeaderSpec crossOriginEmbedderPolicy(
Customizer<CrossOriginEmbedderPolicySpec> crossOriginEmbedderPolicyCustomizer) {
crossOriginEmbedderPolicyCustomizer.customize(new CrossOriginEmbedderPolicySpec());
return this;
}
/**
* Configures the <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
* Cross-Origin-Resource-Policy</a> header.
* @return the {@link CrossOriginResourcePolicySpec} to configure
* @since 5.7
* @see CrossOriginResourcePolicyServerHttpHeadersWriter
*/
public CrossOriginResourcePolicySpec crossOriginResourcePolicy() {
return new CrossOriginResourcePolicySpec();
}
/**
* Configures the <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
* Cross-Origin-Resource-Policy</a> header.
* @return the {@link HeaderSpec} to customize
* @since 5.7
* @see CrossOriginResourcePolicyServerHttpHeadersWriter
*/
public HeaderSpec crossOriginResourcePolicy(
Customizer<CrossOriginResourcePolicySpec> crossOriginResourcePolicyCustomizer) {
crossOriginResourcePolicyCustomizer.customize(new CrossOriginResourcePolicySpec());
return this;
}
/**
* Configures cache control headers
*
@ -2910,6 +3001,99 @@ public class ServerHttpSecurity {
}
/**
* Configures the Cross-Origin-Opener-Policy header
*
* @since 5.7
*/
public final class CrossOriginOpenerPolicySpec {
private CrossOriginOpenerPolicySpec() {
}
/**
* Sets the value to be used in the `Cross-Origin-Opener-Policy` header
* @param openerPolicy a opener policy
* @return the {@link CrossOriginOpenerPolicySpec} to continue configuring
*/
public CrossOriginOpenerPolicySpec policy(CrossOriginOpenerPolicy openerPolicy) {
HeaderSpec.this.crossOriginOpenerPolicy.setPolicy(openerPolicy);
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 the Cross-Origin-Embedder-Policy header
*
* @since 5.7
*/
public final class CrossOriginEmbedderPolicySpec {
private CrossOriginEmbedderPolicySpec() {
}
/**
* Sets the value to be used in the `Cross-Origin-Embedder-Policy` header
* @param embedderPolicy a opener policy
* @return the {@link CrossOriginEmbedderPolicySpec} to continue configuring
*/
public CrossOriginEmbedderPolicySpec policy(CrossOriginEmbedderPolicy embedderPolicy) {
HeaderSpec.this.crossOriginEmbedderPolicy.setPolicy(embedderPolicy);
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 the Cross-Origin-Resource-Policy header
*
* @since 5.7
*/
public final class CrossOriginResourcePolicySpec {
private CrossOriginResourcePolicySpec() {
}
/**
* Sets the value to be used in the `Cross-Origin-Resource-Policy` header
* @param resourcePolicy a opener policy
* @return the {@link CrossOriginResourcePolicySpec} to continue configuring
*/
public CrossOriginResourcePolicySpec policy(CrossOriginResourcePolicy resourcePolicy) {
HeaderSpec.this.crossOriginResourcePolicy.setPolicy(resourcePolicy);
return this;
}
/**
* Allows method chaining to continue configuring the
* {@link ServerHttpSecurity}.
* @return the {@link HeaderSpec} to continue configuring
*/
public HeaderSpec and() {
return HeaderSpec.this;
}
}
}
/**

View File

@ -0,0 +1,42 @@
/*
* Copyright 2002-2021 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.config.annotation.web.builders.HttpSecurity
import org.springframework.security.web.server.header.CrossOriginEmbedderPolicyServerHttpHeadersWriter
/**
* A Kotlin DSL to configure the [HttpSecurity] Cross-Origin-Embedder-Policy header using
* idiomatic Kotlin code.
*
* @author Marcus Da Coregio
* @since 5.7
* @property policy the policy to be used in the response header.
*/
@ServerSecurityMarker
class ServerCrossOriginEmbedderPolicyDsl {
var policy: CrossOriginEmbedderPolicyServerHttpHeadersWriter.CrossOriginEmbedderPolicy? = null
internal fun get(): (ServerHttpSecurity.HeaderSpec.CrossOriginEmbedderPolicySpec) -> Unit {
return { crossOriginEmbedderPolicy ->
policy?.also {
crossOriginEmbedderPolicy.policy(policy)
}
}
}
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2002-2021 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.config.annotation.web.builders.HttpSecurity
import org.springframework.security.web.server.header.CrossOriginOpenerPolicyServerHttpHeadersWriter
/**
* A Kotlin DSL to configure the [HttpSecurity] Cross-Origin-Opener-Policy header using
* idiomatic Kotlin code.
*
* @author Marcus Da Coregio
* @since 5.7
* @property policy the policy to be used in the response header.
*/
@ServerSecurityMarker
class ServerCrossOriginOpenerPolicyDsl {
var policy: CrossOriginOpenerPolicyServerHttpHeadersWriter.CrossOriginOpenerPolicy? = null
internal fun get(): (ServerHttpSecurity.HeaderSpec.CrossOriginOpenerPolicySpec) -> Unit {
return { crossOriginOpenerPolicy ->
policy?.also {
crossOriginOpenerPolicy.policy(policy)
}
}
}
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 2002-2021 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.config.annotation.web.builders.HttpSecurity
import org.springframework.security.web.server.header.CrossOriginResourcePolicyServerHttpHeadersWriter
/**
* A Kotlin DSL to configure the [HttpSecurity] Cross-Origin-Resource-Policy header using
* idiomatic Kotlin code.
*
* @author Marcus Da Coregio
* @since 5.7
* @property policy the policy to be used in the response header.
*/
@ServerSecurityMarker
class ServerCrossOriginResourcePolicyDsl {
var policy: CrossOriginResourcePolicyServerHttpHeadersWriter.CrossOriginResourcePolicy? = null
internal fun get(): (ServerHttpSecurity.HeaderSpec.CrossOriginResourcePolicySpec) -> Unit {
return { crossOriginResourcePolicy ->
policy?.also {
crossOriginResourcePolicy.policy(policy)
}
}
}
}

View File

@ -16,7 +16,12 @@
package org.springframework.security.config.web.server
import org.springframework.security.web.server.header.*
import org.springframework.security.web.server.header.CacheControlServerHttpHeadersWriter
import org.springframework.security.web.server.header.ContentTypeOptionsServerHttpHeadersWriter
import org.springframework.security.web.server.header.ReferrerPolicyServerHttpHeadersWriter
import org.springframework.security.web.server.header.StrictTransportSecurityServerHttpHeadersWriter
import org.springframework.security.web.server.header.XFrameOptionsServerHttpHeadersWriter
import org.springframework.security.web.server.header.XXssProtectionServerHttpHeadersWriter
/**
* A Kotlin DSL to configure [ServerHttpSecurity] headers using idiomatic Kotlin code.
@ -35,6 +40,9 @@ class ServerHeadersDsl {
private var referrerPolicy: ((ServerHttpSecurity.HeaderSpec.ReferrerPolicySpec) -> Unit)? = null
private var featurePolicyDirectives: String? = null
private var permissionsPolicy: ((ServerHttpSecurity.HeaderSpec.PermissionsPolicySpec) -> Unit)? = null
private var crossOriginOpenerPolicy: ((ServerHttpSecurity.HeaderSpec.CrossOriginOpenerPolicySpec) -> Unit)? = null
private var crossOriginEmbedderPolicy: ((ServerHttpSecurity.HeaderSpec.CrossOriginEmbedderPolicySpec) -> Unit)? = null
private var crossOriginResourcePolicy: ((ServerHttpSecurity.HeaderSpec.CrossOriginResourcePolicySpec) -> Unit)? = null
private var disabled = false
@ -157,6 +165,39 @@ class ServerHeadersDsl {
this.permissionsPolicy = ServerPermissionsPolicyDsl().apply(permissionsPolicyConfig).get()
}
/**
* Allows configuration for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
* Cross-Origin-Opener-Policy</a> header.
*
* @since 5.7
* @param crossOriginOpenerPolicyConfig the customization to apply to the header
*/
fun crossOriginOpenerPolicy(crossOriginOpenerPolicyConfig: ServerCrossOriginOpenerPolicyDsl.() -> Unit) {
this.crossOriginOpenerPolicy = ServerCrossOriginOpenerPolicyDsl().apply(crossOriginOpenerPolicyConfig).get()
}
/**
* Allows configuration for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
* Cross-Origin-Embedder-Policy</a> header.
*
* @since 5.7
* @param crossOriginEmbedderPolicyConfig the customization to apply to the header
*/
fun crossOriginEmbedderPolicy(crossOriginEmbedderPolicyConfig: ServerCrossOriginEmbedderPolicyDsl.() -> Unit) {
this.crossOriginEmbedderPolicy = ServerCrossOriginEmbedderPolicyDsl().apply(crossOriginEmbedderPolicyConfig).get()
}
/**
* Allows configuration for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
* Cross-Origin-Resource-Policy</a> header.
*
* @since 5.7
* @param crossOriginResourcePolicyConfig the customization to apply to the header
*/
fun crossOriginResourcePolicy(crossOriginResourcePolicyConfig: ServerCrossOriginResourcePolicyDsl.() -> Unit) {
this.crossOriginResourcePolicy = ServerCrossOriginResourcePolicyDsl().apply(crossOriginResourcePolicyConfig).get()
}
/**
* Disables HTTP response headers.
*/
@ -194,6 +235,15 @@ class ServerHeadersDsl {
referrerPolicy?.also {
headers.referrerPolicy(referrerPolicy)
}
crossOriginOpenerPolicy?.also {
headers.crossOriginOpenerPolicy(crossOriginOpenerPolicy)
}
crossOriginEmbedderPolicy?.also {
headers.crossOriginEmbedderPolicy(crossOriginEmbedderPolicy)
}
crossOriginResourcePolicy?.also {
headers.crossOriginResourcePolicy(crossOriginResourcePolicy)
}
if (disabled) {
headers.disable()
}

View File

@ -42,6 +42,9 @@ class HeadersDsl {
private var referrerPolicy: ((HeadersConfigurer<HttpSecurity>.ReferrerPolicyConfig) -> Unit)? = null
private var featurePolicyDirectives: String? = null
private var permissionsPolicy: ((HeadersConfigurer<HttpSecurity>.PermissionsPolicyConfig) -> Unit)? = null
private var crossOriginOpenerPolicy: ((HeadersConfigurer<HttpSecurity>.CrossOriginOpenerPolicyConfig) -> Unit)? = null
private var crossOriginEmbedderPolicy: ((HeadersConfigurer<HttpSecurity>.CrossOriginEmbedderPolicyConfig) -> Unit)? = null
private var crossOriginResourcePolicy: ((HeadersConfigurer<HttpSecurity>.CrossOriginResourcePolicyConfig) -> Unit)? = null
private var disabled = false
private var headerWriters = mutableListOf<HeaderWriter>()
@ -181,6 +184,54 @@ class HeadersDsl {
this.permissionsPolicy = PermissionsPolicyDsl().apply(permissionsPolicyConfig).get()
}
/**
* Allows configuration for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
* Cross-Origin-Opener-Policy</a> header.
*
* <p>
* Calling this method automatically enables (includes) the Cross-Origin-Opener-Policy
* header in the response using the supplied policy.
* <p>
*
* @since 5.7
* @param crossOriginOpenerPolicyConfig the customization to apply to the header
*/
fun crossOriginOpenerPolicy(crossOriginOpenerPolicyConfig: CrossOriginOpenerPolicyDsl.() -> Unit) {
this.crossOriginOpenerPolicy = CrossOriginOpenerPolicyDsl().apply(crossOriginOpenerPolicyConfig).get()
}
/**
* Allows configuration for <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
* Cross-Origin-Embedder-Policy</a> header.
*
* <p>
* Calling this method automatically enables (includes) the Cross-Origin-Embedder-Policy
* header in the response using the supplied policy.
* <p>
*
* @since 5.7
* @param crossOriginEmbedderPolicyConfig the customization to apply to the header
*/
fun crossOriginEmbedderPolicy(crossOriginEmbedderPolicyConfig: CrossOriginEmbedderPolicyDsl.() -> Unit) {
this.crossOriginEmbedderPolicy = CrossOriginEmbedderPolicyDsl().apply(crossOriginEmbedderPolicyConfig).get()
}
/**
* Configures the <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
* Cross-Origin-Resource-Policy</a> header.
*
* <p>
* Calling this method automatically enables (includes) the Cross-Origin-Resource-Policy
* header in the response using the supplied policy.
* <p>
*
* @since 5.7
* @param crossOriginResourcePolicyConfig the customization to apply to the header
*/
fun crossOriginResourcePolicy(crossOriginResourcePolicyConfig: CrossOriginResourcePolicyDsl.() -> Unit) {
this.crossOriginResourcePolicy = CrossOriginResourcePolicyDsl().apply(crossOriginResourcePolicyConfig).get()
}
/**
* Adds a [HeaderWriter] instance.
*
@ -238,6 +289,15 @@ class HeadersDsl {
permissionsPolicy?.also {
headers.permissionsPolicy(permissionsPolicy)
}
crossOriginOpenerPolicy?.also {
headers.crossOriginOpenerPolicy(crossOriginOpenerPolicy)
}
crossOriginEmbedderPolicy?.also {
headers.crossOriginEmbedderPolicy(crossOriginEmbedderPolicy)
}
crossOriginResourcePolicy?.also {
headers.crossOriginResourcePolicy(crossOriginResourcePolicy)
}
headerWriters.forEach { headerWriter ->
headers.addHeaderWriter(headerWriter)
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2002-2021 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
import org.springframework.security.web.header.writers.CrossOriginEmbedderPolicyHeaderWriter
/**
* A Kotlin DSL to configure the [HttpSecurity] Cross-Origin-Embedder-Policy header using
* idiomatic Kotlin code.
*
* @author Marcus Da Coregio
* @since 5.7
* @property policy the policy to be used in the response header.
*/
@HeadersSecurityMarker
class CrossOriginEmbedderPolicyDsl {
var policy: CrossOriginEmbedderPolicyHeaderWriter.CrossOriginEmbedderPolicy? = null
internal fun get(): (HeadersConfigurer<HttpSecurity>.CrossOriginEmbedderPolicyConfig) -> Unit {
return { crossOriginEmbedderPolicy ->
policy?.also {
crossOriginEmbedderPolicy.policy(policy)
}
}
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2002-2021 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
import org.springframework.security.web.header.writers.CrossOriginOpenerPolicyHeaderWriter
/**
* A Kotlin DSL to configure the [HttpSecurity] Cross-Origin-Opener-Policy header using
* idiomatic Kotlin code.
*
* @author Marcus Da Coregio
* @since 5.7
* @property policy the policy to be used in the response header.
*/
@HeadersSecurityMarker
class CrossOriginOpenerPolicyDsl {
var policy: CrossOriginOpenerPolicyHeaderWriter.CrossOriginOpenerPolicy? = null
internal fun get(): (HeadersConfigurer<HttpSecurity>.CrossOriginOpenerPolicyConfig) -> Unit {
return { crossOriginOpenerPolicy ->
policy?.also {
crossOriginOpenerPolicy.policy(policy)
}
}
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2002-2021 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
import org.springframework.security.web.header.writers.CrossOriginResourcePolicyHeaderWriter
/**
* A Kotlin DSL to configure the [HttpSecurity] Cross-Origin-Resource-Policy header using
* idiomatic Kotlin code.
*
* @author Marcus Da Coregio
* @since 5.7
* @property policy the policy to be used in the response header.
*/
@HeadersSecurityMarker
class CrossOriginResourcePolicyDsl {
var policy: CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy? = null
internal fun get(): (HeadersConfigurer<HttpSecurity>.CrossOriginResourcePolicyConfig) -> Unit {
return { crossOriginResourcePolicy ->
policy?.also {
crossOriginResourcePolicy.policy(policy)
}
}
}
}

View File

@ -943,7 +943,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? & permissions-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? & cross-origin-opener-policy? & cross-origin-embedder-policy? & cross-origin-resource-policy? & header*)}
headers-options.attlist &=
## Specifies if the default headers should be disabled. Default false.
attribute defaults-disabled {xsd:token}?
@ -1092,6 +1092,27 @@ content-type-options.attlist &=
## If disabled, the X-Content-Type-Options header will not be included. Default false.
attribute disabled {xsd:boolean}?
cross-origin-opener-policy =
## Adds support for Cross-Origin-Opener-Policy header
element cross-origin-opener-policy {cross-origin-opener-policy-options.attlist,empty}
cross-origin-opener-policy-options.attlist &=
## The policies for the Cross-Origin-Opener-Policy header.
attribute policy {"unsafe-none","same-origin","same-origin-allow-popups"}?
cross-origin-embedder-policy =
## Adds support for Cross-Origin-Embedder-Policy header
element cross-origin-embedder-policy {cross-origin-embedder-policy-options.attlist,empty}
cross-origin-embedder-policy-options.attlist &=
## The policies for the Cross-Origin-Embedder-Policy header.
attribute policy {"unsafe-none","require-corp"}?
cross-origin-resource-policy =
## Adds support for Cross-Origin-Resource-Policy header
element cross-origin-resource-policy {cross-origin-resource-policy-options.attlist,empty}
cross-origin-resource-policy-options.attlist &=
## The policies for the Cross-Origin-Resource-Policy header.
attribute policy {"cross-origin","same-origin","same-site"}?
header=
## Add additional headers to the response.
element header {header.attlist}

View File

@ -2768,6 +2768,9 @@
<xs:element ref="security:referrer-policy"/>
<xs:element ref="security:feature-policy"/>
<xs:element ref="security:permissions-policy"/>
<xs:element ref="security:cross-origin-opener-policy"/>
<xs:element ref="security:cross-origin-embedder-policy"/>
<xs:element ref="security:cross-origin-resource-policy"/>
<xs:element ref="security:header"/>
</xs:choice>
<xs:attributeGroup ref="security:headers-options.attlist"/>
@ -3151,6 +3154,77 @@
</xs:annotation>
</xs:attribute>
</xs:attributeGroup>
<xs:element name="cross-origin-opener-policy">
<xs:annotation>
<xs:documentation>Adds support for Cross-Origin-Opener-Policy header
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attributeGroup ref="security:cross-origin-opener-policy-options.attlist"/>
</xs:complexType>
</xs:element>
<xs:attributeGroup name="cross-origin-opener-policy-options.attlist">
<xs:attribute name="policy">
<xs:annotation>
<xs:documentation>The policies for the Cross-Origin-Opener-Policy header.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="unsafe-none"/>
<xs:enumeration value="same-origin"/>
<xs:enumeration value="same-origin-allow-popups"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:attributeGroup>
<xs:element name="cross-origin-embedder-policy">
<xs:annotation>
<xs:documentation>Adds support for Cross-Origin-Embedder-Policy header
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attributeGroup ref="security:cross-origin-embedder-policy-options.attlist"/>
</xs:complexType>
</xs:element>
<xs:attributeGroup name="cross-origin-embedder-policy-options.attlist">
<xs:attribute name="policy">
<xs:annotation>
<xs:documentation>The policies for the Cross-Origin-Embedder-Policy header.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="unsafe-none"/>
<xs:enumeration value="require-corp"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:attributeGroup>
<xs:element name="cross-origin-resource-policy">
<xs:annotation>
<xs:documentation>Adds support for Cross-Origin-Resource-Policy header
</xs:documentation>
</xs:annotation>
<xs:complexType>
<xs:attributeGroup ref="security:cross-origin-resource-policy-options.attlist"/>
</xs:complexType>
</xs:element>
<xs:attributeGroup name="cross-origin-resource-policy-options.attlist">
<xs:attribute name="policy">
<xs:annotation>
<xs:documentation>The policies for the Cross-Origin-Resource-Policy header.
</xs:documentation>
</xs:annotation>
<xs:simpleType>
<xs:restriction base="xs:token">
<xs:enumeration value="cross-origin"/>
<xs:enumeration value="same-origin"/>
<xs:enumeration value="same-site"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:attributeGroup>
<xs:element name="header">
<xs:annotation>
<xs:documentation>Add additional headers to the response.

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 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.
@ -26,11 +26,16 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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.SpringTestContext;
import org.springframework.security.config.test.SpringTestContextExtension;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.header.writers.CrossOriginEmbedderPolicyHeaderWriter;
import org.springframework.security.web.header.writers.CrossOriginOpenerPolicyHeaderWriter;
import org.springframework.security.web.header.writers.CrossOriginResourcePolicyHeaderWriter;
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;
@ -52,6 +57,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Eddú Meléndez
* @author Vedran Pavic
* @author Eleftheria Stein
* @author Marcus Da Coregio
*/
@ExtendWith(SpringTestContextExtension.class)
public class HeadersConfigurerTests {
@ -514,6 +520,30 @@ public class HeadersConfigurerTests {
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.STRICT_TRANSPORT_SECURITY);
}
@Test
public void getWhenCustomCrossOriginPoliciesInLambdaThenCrossOriginPolicyHeadersWithCustomValuesInResponse()
throws Exception {
this.spring.register(CrossOriginCustomPoliciesInLambdaConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/"))
.andExpect(header().string(HttpHeaders.CROSS_ORIGIN_OPENER_POLICY, "same-origin"))
.andExpect(header().string(HttpHeaders.CROSS_ORIGIN_EMBEDDER_POLICY, "require-corp"))
.andExpect(header().string(HttpHeaders.CROSS_ORIGIN_RESOURCE_POLICY, "same-origin")).andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.CROSS_ORIGIN_OPENER_POLICY,
HttpHeaders.CROSS_ORIGIN_EMBEDDER_POLICY, HttpHeaders.CROSS_ORIGIN_RESOURCE_POLICY);
}
@Test
public void getWhenCustomCrossOriginPoliciesThenCrossOriginPolicyHeadersWithCustomValuesInResponse()
throws Exception {
this.spring.register(CrossOriginCustomPoliciesConfig.class).autowire();
MvcResult mvcResult = this.mvc.perform(get("/"))
.andExpect(header().string(HttpHeaders.CROSS_ORIGIN_OPENER_POLICY, "same-origin"))
.andExpect(header().string(HttpHeaders.CROSS_ORIGIN_EMBEDDER_POLICY, "require-corp"))
.andExpect(header().string(HttpHeaders.CROSS_ORIGIN_RESOURCE_POLICY, "same-origin")).andReturn();
assertThat(mvcResult.getResponse().getHeaderNames()).containsExactly(HttpHeaders.CROSS_ORIGIN_OPENER_POLICY,
HttpHeaders.CROSS_ORIGIN_EMBEDDER_POLICY, HttpHeaders.CROSS_ORIGIN_RESOURCE_POLICY);
}
@EnableWebSecurity
static class HeadersConfig extends WebSecurityConfigurerAdapter {
@ -1146,4 +1176,50 @@ public class HeadersConfigurerTests {
}
@EnableWebSecurity
static class CrossOriginCustomPoliciesInLambdaConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// @formatter:off
http.headers((headers) -> headers
.defaultsDisabled()
.crossOriginOpenerPolicy((policy) -> policy
.policy(CrossOriginOpenerPolicyHeaderWriter.CrossOriginOpenerPolicy.SAME_ORIGIN)
)
.crossOriginEmbedderPolicy((policy) -> policy
.policy(CrossOriginEmbedderPolicyHeaderWriter.CrossOriginEmbedderPolicy.REQUIRE_CORP)
)
.crossOriginResourcePolicy((policy) -> policy
.policy(CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy.SAME_ORIGIN)
)
);
// @formatter:on
return http.build();
}
}
@EnableWebSecurity
static class CrossOriginCustomPoliciesConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// @formatter:off
http.headers()
.defaultsDisabled()
.crossOriginOpenerPolicy()
.policy(CrossOriginOpenerPolicyHeaderWriter.CrossOriginOpenerPolicy.SAME_ORIGIN)
.and()
.crossOriginEmbedderPolicy()
.policy(CrossOriginEmbedderPolicyHeaderWriter.CrossOriginEmbedderPolicy.REQUIRE_CORP)
.and()
.crossOriginResourcePolicy()
.policy(CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy.SAME_ORIGIN);
// @formatter:on
return http.build();
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 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.
@ -48,6 +48,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
* @author Tim Ysewyn
* @author Josh Cummings
* @author Rafiullah Hamedy
* @author Marcus Da Coregio
*/
@ExtendWith(SpringTestContextExtension.class)
public class HttpHeadersConfigTests {
@ -733,6 +734,53 @@ public class HttpHeadersConfigTests {
// @formatter:on
}
@Test
public void requestWhenCrossOriginOpenerPolicyWithSameOriginAllowPopupsThenRespondsWithSameOriginAllowPopups()
throws Exception {
this.spring.configLocations(this.xml("DefaultsDisabledWithCrossOriginOpenerPolicy")).autowire();
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(excludesDefaults())
.andExpect(header().string("Cross-Origin-Opener-Policy", "same-origin-allow-popups"));
// @formatter:on
}
@Test
public void requestWhenCrossOriginEmbedderPolicyWithRequireCorpThenRespondsWithRequireCorp() throws Exception {
this.spring.configLocations(this.xml("DefaultsDisabledWithCrossOriginEmbedderPolicy")).autowire();
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(excludesDefaults())
.andExpect(header().string("Cross-Origin-Embedder-Policy", "require-corp"));
// @formatter:on
}
@Test
public void requestWhenCrossOriginResourcePolicyWithSameOriginThenRespondsWithSameOrigin() throws Exception {
this.spring.configLocations(this.xml("DefaultsDisabledWithCrossOriginResourcePolicy")).autowire();
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(excludesDefaults())
.andExpect(header().string("Cross-Origin-Resource-Policy", "same-origin"));
// @formatter:on
}
@Test
public void requestWhenCrossOriginPoliciesRespondsCrossOriginPolicies() throws Exception {
this.spring.configLocations(this.xml("DefaultsDisabledWithCrossOriginPolicies")).autowire();
// @formatter:off
this.mvc.perform(get("/"))
.andExpect(status().isOk())
.andExpect(excludesDefaults())
.andExpect(header().string("Cross-Origin-Opener-Policy", "same-origin"))
.andExpect(header().string("Cross-Origin-Embedder-Policy", "require-corp"))
.andExpect(header().string("Cross-Origin-Resource-Policy", "same-origin"));
// @formatter:on
}
private static ResultMatcher includesDefaults() {
return includes(defaultHeaders);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2019 the original author or authors.
* Copyright 2002-2021 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.
@ -30,6 +30,9 @@ import org.springframework.http.HttpHeaders;
import org.springframework.security.test.web.reactive.server.WebTestClientBuilder;
import org.springframework.security.web.server.header.ContentSecurityPolicyServerHttpHeadersWriter;
import org.springframework.security.web.server.header.ContentTypeOptionsServerHttpHeadersWriter;
import org.springframework.security.web.server.header.CrossOriginEmbedderPolicyServerHttpHeadersWriter;
import org.springframework.security.web.server.header.CrossOriginOpenerPolicyServerHttpHeadersWriter;
import org.springframework.security.web.server.header.CrossOriginResourcePolicyServerHttpHeadersWriter;
import org.springframework.security.web.server.header.FeaturePolicyServerHttpHeadersWriter;
import org.springframework.security.web.server.header.ReferrerPolicyServerHttpHeadersWriter;
import org.springframework.security.web.server.header.ReferrerPolicyServerHttpHeadersWriter.ReferrerPolicy;
@ -48,6 +51,7 @@ import static org.springframework.security.config.Customizer.withDefaults;
* @author Rob Winch
* @author Vedran Pavic
* @author Ankur Pathak
* @author Marcus Da Coregio
* @since 5.0
*/
public class HeaderSpecTests {
@ -406,6 +410,53 @@ public class HeaderSpecTests {
assertHeaders();
}
@Test
public void headersWhenCrossOriginPoliciesCustomEnabledThenCustomCrossOriginPoliciesWritten() {
this.expectedHeaders.add(CrossOriginOpenerPolicyServerHttpHeadersWriter.OPENER_POLICY,
CrossOriginOpenerPolicyServerHttpHeadersWriter.CrossOriginOpenerPolicy.SAME_ORIGIN_ALLOW_POPUPS
.getPolicy());
this.expectedHeaders.add(CrossOriginEmbedderPolicyServerHttpHeadersWriter.EMBEDDER_POLICY,
CrossOriginEmbedderPolicyServerHttpHeadersWriter.CrossOriginEmbedderPolicy.REQUIRE_CORP.getPolicy());
this.expectedHeaders.add(CrossOriginResourcePolicyServerHttpHeadersWriter.RESOURCE_POLICY,
CrossOriginResourcePolicyServerHttpHeadersWriter.CrossOriginResourcePolicy.SAME_ORIGIN.getPolicy());
// @formatter:off
this.http.headers()
.crossOriginOpenerPolicy()
.policy(CrossOriginOpenerPolicyServerHttpHeadersWriter.CrossOriginOpenerPolicy.SAME_ORIGIN_ALLOW_POPUPS)
.and()
.crossOriginEmbedderPolicy()
.policy(CrossOriginEmbedderPolicyServerHttpHeadersWriter.CrossOriginEmbedderPolicy.REQUIRE_CORP)
.and()
.crossOriginResourcePolicy()
.policy(CrossOriginResourcePolicyServerHttpHeadersWriter.CrossOriginResourcePolicy.SAME_ORIGIN);
// @formatter:on
assertHeaders();
}
@Test
public void headersWhenCrossOriginPoliciesCustomEnabledInLambdaThenCustomCrossOriginPoliciesWritten() {
this.expectedHeaders.add(CrossOriginOpenerPolicyServerHttpHeadersWriter.OPENER_POLICY,
CrossOriginOpenerPolicyServerHttpHeadersWriter.CrossOriginOpenerPolicy.SAME_ORIGIN_ALLOW_POPUPS
.getPolicy());
this.expectedHeaders.add(CrossOriginEmbedderPolicyServerHttpHeadersWriter.EMBEDDER_POLICY,
CrossOriginEmbedderPolicyServerHttpHeadersWriter.CrossOriginEmbedderPolicy.REQUIRE_CORP.getPolicy());
this.expectedHeaders.add(CrossOriginResourcePolicyServerHttpHeadersWriter.RESOURCE_POLICY,
CrossOriginResourcePolicyServerHttpHeadersWriter.CrossOriginResourcePolicy.SAME_ORIGIN.getPolicy());
// @formatter:off
this.http.headers()
.crossOriginOpenerPolicy((policy) -> policy
.policy(CrossOriginOpenerPolicyServerHttpHeadersWriter.CrossOriginOpenerPolicy.SAME_ORIGIN_ALLOW_POPUPS)
)
.crossOriginEmbedderPolicy((policy) -> policy
.policy(CrossOriginEmbedderPolicyServerHttpHeadersWriter.CrossOriginEmbedderPolicy.REQUIRE_CORP)
)
.crossOriginResourcePolicy((policy) -> policy
.policy(CrossOriginResourcePolicyServerHttpHeadersWriter.CrossOriginResourcePolicy.SAME_ORIGIN)
);
// @formatter:on
assertHeaders();
}
private void expectHeaderNamesNotPresent(String... headerNames) {
for (String headerName : headerNames) {
this.expectedHeaders.remove(headerName);

View File

@ -28,6 +28,9 @@ import org.springframework.security.config.test.SpringTestContextExtension
import org.springframework.security.web.header.writers.frameoptions.XFrameOptionsHeaderWriter
import org.springframework.security.web.server.SecurityWebFilterChain
import org.springframework.security.web.server.header.ContentTypeOptionsServerHttpHeadersWriter
import org.springframework.security.web.server.header.CrossOriginEmbedderPolicyServerHttpHeadersWriter
import org.springframework.security.web.server.header.CrossOriginOpenerPolicyServerHttpHeadersWriter
import org.springframework.security.web.server.header.CrossOriginResourcePolicyServerHttpHeadersWriter
import org.springframework.security.web.server.header.StrictTransportSecurityServerHttpHeadersWriter
import org.springframework.security.web.server.header.XFrameOptionsServerHttpHeadersWriter
import org.springframework.security.web.server.header.XXssProtectionServerHttpHeadersWriter
@ -133,4 +136,60 @@ class ServerHeadersDslTests {
}
}
}
@Test
fun `request when no cross-origin policies configured then does not write cross-origin policies headers in response`() {
this.spring.register(CrossOriginPoliciesConfig::class.java).autowire()
this.client.get()
.uri("/")
.exchange()
.expectHeader().doesNotExist("Cross-Origin-Opener-Policy")
.expectHeader().doesNotExist("Cross-Origin-Embedder-Policy")
.expectHeader().doesNotExist("Cross-Origin-Resource-Policy")
}
@EnableWebFluxSecurity
@EnableWebFlux
open class CrossOriginPoliciesConfig {
@Bean
open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
return http {
headers { }
}
}
}
@Test
fun `request when cross-origin custom policies configured then cross-origin custom policies headers in response`() {
this.spring.register(CrossOriginPoliciesCustomConfig::class.java).autowire()
this.client.get()
.uri("/")
.exchange()
.expectHeader().valueEquals("Cross-Origin-Opener-Policy", "same-origin")
.expectHeader().valueEquals("Cross-Origin-Embedder-Policy", "require-corp")
.expectHeader().valueEquals("Cross-Origin-Resource-Policy", "same-origin")
}
@EnableWebFluxSecurity
@EnableWebFlux
open class CrossOriginPoliciesCustomConfig {
@Bean
open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
return http {
headers {
crossOriginOpenerPolicy {
policy = CrossOriginOpenerPolicyServerHttpHeadersWriter.CrossOriginOpenerPolicy.SAME_ORIGIN
}
crossOriginEmbedderPolicy {
policy = CrossOriginEmbedderPolicyServerHttpHeadersWriter.CrossOriginEmbedderPolicy.REQUIRE_CORP
}
crossOriginResourcePolicy {
policy = CrossOriginResourcePolicyServerHttpHeadersWriter.CrossOriginResourcePolicy.SAME_ORIGIN
}
}
}
}
}
}

View File

@ -19,13 +19,13 @@ package org.springframework.security.config.web.servlet
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Bean
import org.springframework.http.HttpHeaders
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.SpringTestContext
import org.springframework.security.config.test.SpringTestContextExtension
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

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2002-2021 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">
<cross-origin-embedder-policy policy="require-corp"/>
</headers>
</http>
<b:bean name="simple" class="org.springframework.security.config.http.HttpHeadersConfigTests.SimpleController"/>
<b:import resource="userservice.xml"/>
</b:beans>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2002-2021 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">
<cross-origin-opener-policy policy="same-origin-allow-popups"/>
</headers>
</http>
<b:bean name="simple" class="org.springframework.security.config.http.HttpHeadersConfigTests.SimpleController"/>
<b:import resource="userservice.xml"/>
</b:beans>

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2002-2021 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">
<cross-origin-opener-policy policy="same-origin"/>
<cross-origin-embedder-policy policy="require-corp"/>
<cross-origin-resource-policy policy="same-origin"/>
</headers>
</http>
<b:bean name="simple" class="org.springframework.security.config.http.HttpHeadersConfigTests.SimpleController"/>
<b:import resource="userservice.xml"/>
</b:beans>

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 2002-2021 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">
<cross-origin-resource-policy policy="same-origin"/>
</headers>
</http>
<b:bean name="simple" class="org.springframework.security.config.http.HttpHeadersConfigTests.SimpleController"/>
<b:import resource="userservice.xml"/>
</b:beans>

View File

@ -378,6 +378,26 @@ Clear-Site-Data: "cache", "cookies", "storage", "executionContexts"
This is a nice clean-up action to perform on logout.
[[headers-cross-origin-policies]]
== Cross-Origin Policies
[NOTE]
====
Refer to the relevant sections to see how to configure for both <<servlet-headers-cross-origin-policies,servlet>> and <<webflux-headers-cross-origin-policies,webflux>> based applications.
====
Spring Security provides support for some important Cross-Origin Policies headers.
Those headers are:
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy[`Cross-Origin-Opener-Policy`]
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy[`Cross-Origin-Embedder-Policy`]
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy[`Cross-Origin-Resource-Policy`]
`Cross-Origin-Opener-Policy` (COOP) allows a top-level document to break the association between its window and any others in the browsing context group (e.g., between a popup and its opener), preventing any direct DOM access between them.
Enabling `Cross-Origin-Embedder-Policy` (COEP) prevents a document from loading any non-same-origin resources which don't explicitly grant the document permission to be loaded.
The `Cross-Origin-Resource-Policy` (CORP) header allows you to control the set of origins that are empowered to include a resource. It is a robust defense against attacks like https://meltdownattack.com[Spectre], as it allows browsers to block a given response before it enters an attacker's process.
[[headers-custom]]
== Custom Headers

View File

@ -578,3 +578,65 @@ fun webFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
}
----
====
[[webflux-headers-cross-origin-policies]]
== Cross-Origin Policies
Spring Security provides built-in support for adding some Cross-Origin policies headers, those headers are:
[source]
----
Cross-Origin-Opener-Policy
Cross-Origin-Embedder-Policy
Cross-Origin-Resource-Policy
----
Spring Security does not add <<headers-cross-origin-policies,Cross-Origin Policies>> headers by default.
The headers can be added with the following configuration:
.Cross-Origin Policies
====
.Java
[source,java,role="primary"]
----
@EnableWebFluxSecurity
@EnableWebFlux
public class WebSecurityConfig {
@Bean
SecurityWebFilterChain securityFilterChain(ServerHttpSecurity http) {
http.headers((headers) -> headers
.crossOriginOpenerPolicy(CrossOriginOpenerPolicy.SAME_ORIGIN)
.crossOriginEmbedderPolicy(CrossOriginEmbedderPolicy.REQUIRE_CORP)
.crossOriginResourcePolicy(CrossOriginResourcePolicy.SAME_ORIGIN));
return http.build();
}
}
----
.Kotlin
[source,kotlin,role="secondary"]
----
@EnableWebFluxSecurity
@EnableWebFlux
open class CrossOriginPoliciesCustomConfig {
@Bean
open fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain {
return http {
headers {
crossOriginOpenerPolicy(CrossOriginOpenerPolicy.SAME_ORIGIN)
crossOriginEmbedderPolicy(CrossOriginEmbedderPolicy.REQUIRE_CORP)
crossOriginResourcePolicy(CrossOriginResourcePolicy.SAME_ORIGIN)
}
}
}
}
----
====
This configuration will write the headers with the values provided:
[source]
----
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy: same-origin
----

View File

@ -238,6 +238,9 @@ This allows HTTPS websites to resist impersonation by attackers using mis-issued
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.
** `Feature-Policy` - Can be set using the <<nsa-feature-policy,feature-policy>> element, https://wicg.github.io/feature-policy/[Feature-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.
** `Cross-Origin-Opener-Policy` - Can be set using the <<nsa-cross-origin-opener-policy,cross-origin-opener-policy>> element, https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy[Cross-Origin-Opener-Policy] is a mechanism that allows you to ensure a top-level document does not share a browsing context group with cross-origin documents.
** `Cross-Origin-Embedder-Policy` - Can be set using the <<nsa-cross-origin-embedder-policy,cross-origin-embedder-policy>> element, https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy[Cross-Origin-Embedder-Policy] is a mechanism that prevents a document from loading any cross-origin resources that don't explicitly grant the document permission.
** `Cross-Origin-Resource-Policy` - Can be set using the <<nsa-cross-origin-resource-policy,cross-origin-resource-policy>> element, https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy[Cross-Origin-Resource-Policy] is a mechanism that conveys a desire that the browser blocks no-cors cross-origin/cross-site requests to the given resource.
[[nsa-headers-attributes]]
=== <headers> Attributes
@ -269,6 +272,9 @@ The default is false (the headers are enabled).
* <<nsa-cache-control,cache-control>>
* <<nsa-content-security-policy,content-security-policy>>
* <<nsa-content-type-options,content-type-options>>
* <<nsa-cross-origin-embedder-policy,cross-origin-embedder-policy>>
* <<nsa-cross-origin-opener-policy,cross-origin-opener-policy>>
* <<nsa-cross-origin-resource-policy,cross-origin-resource-policy>>
* <<nsa-feature-policy,feature-policy>>
* <<nsa-frame-options,frame-options>>
* <<nsa-header,header>>
@ -584,6 +590,66 @@ Default false.
[[nsa-cross-origin-embedder-policy]]
==== <cross-origin-embedder-policy>
When enabled adds the https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy[Cross-Origin-Embedder-Policy] header to the response.
[[nsa-cross-origin-embedder-policy-attributes]]
===== <cross-origin-embedder-policy> Attributes
[[nsa-cross-origin-embedder-policy-policy]]
* **policy**
The policy for the `Cross-Origin-Embedder-Policy` header.
[[nsa-cross-origin-embedder-policy-parents]]
===== Parent Elements of <cross-origin-embedder-policy>
* <<nsa-headers,headers>>
[[nsa-cross-origin-opener-policy]]
==== <cross-origin-opener-policy>
When enabled adds the https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy[Cross-Origin-Opener-Policy] header to the response.
[[nsa-cross-origin-opener-policy-attributes]]
===== <cross-origin-opener-policy> Attributes
[[nsa-cross-origin-opener-policy-policy]]
* **policy**
The policy for the `Cross-Origin-Opener-Policy` header.
[[nsa-cross-origin-opener-policy-parents]]
===== Parent Elements of <cross-origin-opener-policy>
* <<nsa-headers,headers>>
[[nsa-cross-origin-resource-policy]]
==== <cross-origin-resource-policy>
When enabled adds the https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy[Cross-Origin-Resource-Policy] header to the response.
[[nsa-cross-origin-resource-policy-attributes]]
===== <cross-origin-resource-policy> Attributes
[[nsa-cross-origin-resource-policy-policy]]
* **policy**
The policy for the `Cross-Origin-Resource-Policy` header.
[[nsa-cross-origin-resource-policy-parents]]
===== Parent Elements of <cross-origin-resource-policy>
* <<nsa-headers,headers>>
[[nsa-header]]
== <header>
Add additional headers to the response, both the name and value need to be specified.

View File

@ -938,6 +938,67 @@ class SecurityConfig : WebSecurityConfigurerAdapter() {
----
====
[[servlet-headers-cross-origin-policies]]
== Cross-Origin Policies
Spring Security provides built-in support for adding some Cross-Origin policies headers, those headers are:
[source]
----
Cross-Origin-Opener-Policy
Cross-Origin-Embedder-Policy
Cross-Origin-Resource-Policy
----
Spring Security does not add <<headers-cross-origin-policies,Cross-Origin Policies>> headers by default.
The headers can be added with the following configuration:
.Cross-Origin Policies
====
.Java
[source,java,role="primary"]
----
@EnableWebSecurity
public class WebSecurityConfig {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) {
http.headers((headers) -> headers
.crossOriginOpenerPolicy(CrossOriginOpenerPolicy.SAME_ORIGIN)
.crossOriginEmbedderPolicy(CrossOriginEmbedderPolicy.REQUIRE_CORP)
.crossOriginResourcePolicy(CrossOriginResourcePolicy.SAME_ORIGIN)));
return http.build();
}
}
----
.Kotlin
[source,kotlin,role="secondary"]
----
@EnableWebSecurity
open class CrossOriginPoliciesConfig {
@Bean
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
headers {
crossOriginOpenerPolicy(CrossOriginOpenerPolicy.SAME_ORIGIN)
crossOriginEmbedderPolicy(CrossOriginEmbedderPolicy.REQUIRE_CORP)
crossOriginResourcePolicy(CrossOriginResourcePolicy.SAME_ORIGIN)
}
}
return http.build()
}
}
----
====
This configuration will write the headers with the values provided:
[source]
----
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Resource-Policy: same-origin
----
[[servlet-headers-custom]]
== Custom Headers
Spring Security has mechanisms to make it convenient to add the more common security headers to your application.

View File

@ -0,0 +1,84 @@
/*
* Copyright 2002-2021 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;
/**
* Inserts Cross-Origin-Embedder-Policy header.
*
* @author Marcus Da Coregio
* @since 5.7
* @see <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
* Cross-Origin-Embedder-Policy</a>
*/
public final class CrossOriginEmbedderPolicyHeaderWriter implements HeaderWriter {
private static final String EMBEDDER_POLICY = "Cross-Origin-Embedder-Policy";
private CrossOriginEmbedderPolicy policy;
/**
* Sets the {@link CrossOriginEmbedderPolicy} value to be used in the
* {@code Cross-Origin-Embedder-Policy} header
* @param embedderPolicy the {@link CrossOriginEmbedderPolicy} to use
*/
public void setPolicy(CrossOriginEmbedderPolicy embedderPolicy) {
Assert.notNull(embedderPolicy, "embedderPolicy cannot be null");
this.policy = embedderPolicy;
}
@Override
public void writeHeaders(HttpServletRequest request, HttpServletResponse response) {
if (this.policy != null && !response.containsHeader(EMBEDDER_POLICY)) {
response.addHeader(EMBEDDER_POLICY, this.policy.getPolicy());
}
}
public enum CrossOriginEmbedderPolicy {
UNSAFE_NONE("unsafe-none"),
REQUIRE_CORP("require-corp");
private final String policy;
CrossOriginEmbedderPolicy(String policy) {
this.policy = policy;
}
public String getPolicy() {
return this.policy;
}
public static CrossOriginEmbedderPolicy from(String embedderPolicy) {
for (CrossOriginEmbedderPolicy policy : values()) {
if (policy.getPolicy().equals(embedderPolicy)) {
return policy;
}
}
return null;
}
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright 2002-2021 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;
/**
* Inserts the Cross-Origin-Opener-Policy header
*
* @author Marcus Da Coregio
* @since 5.7
* @see <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
* Cross-Origin-Opener-Policy</a>
*/
public final class CrossOriginOpenerPolicyHeaderWriter implements HeaderWriter {
private static final String OPENER_POLICY = "Cross-Origin-Opener-Policy";
private CrossOriginOpenerPolicy policy;
/**
* Sets the {@link CrossOriginOpenerPolicy} value to be used in the
* {@code Cross-Origin-Opener-Policy} header
* @param openerPolicy the {@link CrossOriginOpenerPolicy} to use
*/
public void setPolicy(CrossOriginOpenerPolicy openerPolicy) {
Assert.notNull(openerPolicy, "openerPolicy cannot be null");
this.policy = openerPolicy;
}
@Override
public void writeHeaders(HttpServletRequest request, HttpServletResponse response) {
if (this.policy != null && !response.containsHeader(OPENER_POLICY)) {
response.addHeader(OPENER_POLICY, this.policy.getPolicy());
}
}
public enum CrossOriginOpenerPolicy {
UNSAFE_NONE("unsafe-none"),
SAME_ORIGIN_ALLOW_POPUPS("same-origin-allow-popups"),
SAME_ORIGIN("same-origin");
private final String policy;
CrossOriginOpenerPolicy(String policy) {
this.policy = policy;
}
public String getPolicy() {
return this.policy;
}
public static CrossOriginOpenerPolicy from(String openerPolicy) {
for (CrossOriginOpenerPolicy policy : values()) {
if (policy.getPolicy().equals(openerPolicy)) {
return policy;
}
}
return null;
}
}
}

View File

@ -0,0 +1,86 @@
/*
* Copyright 2002-2021 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;
/**
* Inserts Cross-Origin-Resource-Policy header
*
* @author Marcus Da Coregio
* @since 5.7
* @see <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
* Cross-Origin-Resource-Policy</a>
*/
public final class CrossOriginResourcePolicyHeaderWriter implements HeaderWriter {
private static final String RESOURCE_POLICY = "Cross-Origin-Resource-Policy";
private CrossOriginResourcePolicy policy;
/**
* Sets the {@link CrossOriginResourcePolicy} value to be used in the
* {@code Cross-Origin-Resource-Policy} header
* @param resourcePolicy the {@link CrossOriginResourcePolicy} to use
*/
public void setPolicy(CrossOriginResourcePolicy resourcePolicy) {
Assert.notNull(resourcePolicy, "resourcePolicy cannot be null");
this.policy = resourcePolicy;
}
@Override
public void writeHeaders(HttpServletRequest request, HttpServletResponse response) {
if (this.policy != null && !response.containsHeader(RESOURCE_POLICY)) {
response.addHeader(RESOURCE_POLICY, this.policy.getPolicy());
}
}
public enum CrossOriginResourcePolicy {
SAME_SITE("same-site"),
SAME_ORIGIN("same-origin"),
CROSS_ORIGIN("cross-origin");
private final String policy;
CrossOriginResourcePolicy(String policy) {
this.policy = policy;
}
public String getPolicy() {
return this.policy;
}
public static CrossOriginResourcePolicy from(String resourcePolicy) {
for (CrossOriginResourcePolicy policy : values()) {
if (policy.getPolicy().equals(resourcePolicy)) {
return policy;
}
}
return null;
}
}
}

View File

@ -0,0 +1,78 @@
/*
* Copyright 2002-2021 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.util.Assert;
import org.springframework.web.server.ServerWebExchange;
/**
* Inserts Cross-Origin-Embedder-Policy headers.
*
* @author Marcus Da Coregio
* @since 5.7
* @see <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Embedder-Policy">
* Cross-Origin-Embedder-Policy</a>
*/
public final class CrossOriginEmbedderPolicyServerHttpHeadersWriter implements ServerHttpHeadersWriter {
public static final String EMBEDDER_POLICY = "Cross-Origin-Embedder-Policy";
private ServerHttpHeadersWriter delegate;
/**
* Sets the {@link CrossOriginEmbedderPolicy} value to be used in the
* {@code Cross-Origin-Embedder-Policy} header
* @param embedderPolicy the {@link CrossOriginEmbedderPolicy} to use
*/
public void setPolicy(CrossOriginEmbedderPolicy embedderPolicy) {
Assert.notNull(embedderPolicy, "embedderPolicy cannot be null");
this.delegate = createDelegate(embedderPolicy);
}
@Override
public Mono<Void> writeHttpHeaders(ServerWebExchange exchange) {
return (this.delegate != null) ? this.delegate.writeHttpHeaders(exchange) : Mono.empty();
}
private static ServerHttpHeadersWriter createDelegate(CrossOriginEmbedderPolicy embedderPolicy) {
StaticServerHttpHeadersWriter.Builder builder = StaticServerHttpHeadersWriter.builder();
builder.header(EMBEDDER_POLICY, embedderPolicy.getPolicy());
return builder.build();
}
public enum CrossOriginEmbedderPolicy {
UNSAFE_NONE("unsafe-none"),
REQUIRE_CORP("require-corp");
private final String policy;
CrossOriginEmbedderPolicy(String policy) {
this.policy = policy;
}
public String getPolicy() {
return this.policy;
}
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright 2002-2021 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.util.Assert;
import org.springframework.web.server.ServerWebExchange;
/**
* Inserts Cross-Origin-Opener-Policy header.
*
* @author Marcus Da Coregio
* @since 5.7
* @see <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Opener-Policy">
* Cross-Origin-Opener-Policy</a>
*/
public final class CrossOriginOpenerPolicyServerHttpHeadersWriter implements ServerHttpHeadersWriter {
public static final String OPENER_POLICY = "Cross-Origin-Opener-Policy";
private ServerHttpHeadersWriter delegate;
/**
* Sets the {@link CrossOriginOpenerPolicy} value to be used in the
* {@code Cross-Origin-Opener-Policy} header
* @param openerPolicy the {@link CrossOriginOpenerPolicy} to use
*/
public void setPolicy(CrossOriginOpenerPolicy openerPolicy) {
Assert.notNull(openerPolicy, "openerPolicy cannot be null");
this.delegate = createDelegate(openerPolicy);
}
@Override
public Mono<Void> writeHttpHeaders(ServerWebExchange exchange) {
return (this.delegate != null) ? this.delegate.writeHttpHeaders(exchange) : Mono.empty();
}
private static ServerHttpHeadersWriter createDelegate(CrossOriginOpenerPolicy openerPolicy) {
StaticServerHttpHeadersWriter.Builder builder = StaticServerHttpHeadersWriter.builder();
builder.header(OPENER_POLICY, openerPolicy.getPolicy());
return builder.build();
}
public enum CrossOriginOpenerPolicy {
UNSAFE_NONE("unsafe-none"),
SAME_ORIGIN_ALLOW_POPUPS("same-origin-allow-popups"),
SAME_ORIGIN("same-origin");
private final String policy;
CrossOriginOpenerPolicy(String policy) {
this.policy = policy;
}
public String getPolicy() {
return this.policy;
}
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright 2002-2021 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.util.Assert;
import org.springframework.web.server.ServerWebExchange;
/**
* Inserts Cross-Origin-Resource-Policy headers.
*
* @author Marcus Da Coregio
* @since 5.7
* @see <a href=
* "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cross-Origin-Resource-Policy">
* Cross-Origin-Resource-Policy</a>
*/
public final class CrossOriginResourcePolicyServerHttpHeadersWriter implements ServerHttpHeadersWriter {
public static final String RESOURCE_POLICY = "Cross-Origin-Resource-Policy";
private ServerHttpHeadersWriter delegate;
/**
* Sets the {@link CrossOriginResourcePolicy} value to be used in the
* {@code Cross-Origin-Embedder-Policy} header
* @param resourcePolicy the {@link CrossOriginResourcePolicy} to use
*/
public void setPolicy(CrossOriginResourcePolicy resourcePolicy) {
Assert.notNull(resourcePolicy, "resourcePolicy cannot be null");
this.delegate = createDelegate(resourcePolicy);
}
@Override
public Mono<Void> writeHttpHeaders(ServerWebExchange exchange) {
return (this.delegate != null) ? this.delegate.writeHttpHeaders(exchange) : Mono.empty();
}
private static ServerHttpHeadersWriter createDelegate(CrossOriginResourcePolicy resourcePolicy) {
StaticServerHttpHeadersWriter.Builder builder = StaticServerHttpHeadersWriter.builder();
builder.header(RESOURCE_POLICY, resourcePolicy.getPolicy());
return builder.build();
}
public enum CrossOriginResourcePolicy {
SAME_SITE("same-site"),
SAME_ORIGIN("same-origin"),
CROSS_ORIGIN("cross-origin");
private final String policy;
CrossOriginResourcePolicy(String policy) {
this.policy = policy;
}
public String getPolicy() {
return this.policy;
}
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright 2002-2021 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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.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;
class CrossOriginEmbedderPolicyHeaderWriterTests {
private static final String EMBEDDER_HEADER_NAME = "Cross-Origin-Embedder-Policy";
private CrossOriginEmbedderPolicyHeaderWriter writer;
private MockHttpServletRequest request;
private MockHttpServletResponse response;
@BeforeEach
void setup() {
this.writer = new CrossOriginEmbedderPolicyHeaderWriter();
this.request = new MockHttpServletRequest();
this.response = new MockHttpServletResponse();
}
@Test
void setEmbedderPolicyWhenNullEmbedderPolicyThenThrowsIllegalArgument() {
assertThatIllegalArgumentException().isThrownBy(() -> this.writer.setPolicy(null))
.withMessage("embedderPolicy cannot be null");
}
@Test
void writeHeadersWhenDefaultValuesThenDontWriteHeaders() {
this.writer.writeHeaders(this.request, this.response);
assertThat(this.response.getHeaderNames()).hasSize(0);
}
@Test
void writeHeadersWhenResponseHeaderExistsThenDontOverride() {
this.response.addHeader(EMBEDDER_HEADER_NAME, "require-corp");
this.writer.setPolicy(CrossOriginEmbedderPolicyHeaderWriter.CrossOriginEmbedderPolicy.UNSAFE_NONE);
this.writer.writeHeaders(this.request, this.response);
assertThat(this.response.getHeader(EMBEDDER_HEADER_NAME)).isEqualTo("require-corp");
}
@Test
void writeHeadersWhenSetHeaderValuesThenWrites() {
this.writer.setPolicy(CrossOriginEmbedderPolicyHeaderWriter.CrossOriginEmbedderPolicy.REQUIRE_CORP);
this.writer.writeHeaders(this.request, this.response);
assertThat(this.response.getHeader(EMBEDDER_HEADER_NAME)).isEqualTo("require-corp");
}
@Test
void writeHeadersWhenSetEmbedderPolicyThenWritesEmbedderPolicy() {
this.writer.setPolicy(CrossOriginEmbedderPolicyHeaderWriter.CrossOriginEmbedderPolicy.UNSAFE_NONE);
this.writer.writeHeaders(this.request, this.response);
assertThat(this.response.getHeaderNames()).hasSize(1);
assertThat(this.response.getHeader(EMBEDDER_HEADER_NAME)).isEqualTo("unsafe-none");
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright 2002-2021 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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.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;
class CrossOriginOpenerPolicyHeaderWriterTests {
private static final String OPENER_HEADER_NAME = "Cross-Origin-Opener-Policy";
private CrossOriginOpenerPolicyHeaderWriter writer;
private MockHttpServletRequest request;
private MockHttpServletResponse response;
@BeforeEach
void setup() {
this.writer = new CrossOriginOpenerPolicyHeaderWriter();
this.request = new MockHttpServletRequest();
this.response = new MockHttpServletResponse();
}
@Test
void setOpenerPolicyWhenNullOpenerPolicyThenThrowsIllegalArgument() {
assertThatIllegalArgumentException().isThrownBy(() -> this.writer.setPolicy(null))
.withMessage("openerPolicy cannot be null");
}
@Test
void writeHeadersWhenDefaultValuesThenDontWriteHeaders() {
this.writer.writeHeaders(this.request, this.response);
assertThat(this.response.getHeaderNames()).hasSize(0);
}
@Test
void writeHeadersWhenResponseHeaderExistsThenDontOverride() {
this.response.addHeader(OPENER_HEADER_NAME, "same-origin");
this.writer.setPolicy(CrossOriginOpenerPolicyHeaderWriter.CrossOriginOpenerPolicy.SAME_ORIGIN_ALLOW_POPUPS);
this.writer.writeHeaders(this.request, this.response);
assertThat(this.response.getHeader(OPENER_HEADER_NAME)).isEqualTo("same-origin");
}
@Test
void writeHeadersWhenSetHeaderValuesThenWrites() {
this.writer.setPolicy(CrossOriginOpenerPolicyHeaderWriter.CrossOriginOpenerPolicy.SAME_ORIGIN_ALLOW_POPUPS);
this.writer.writeHeaders(this.request, this.response);
assertThat(this.response.getHeader(OPENER_HEADER_NAME)).isEqualTo("same-origin-allow-popups");
}
@Test
void writeHeadersWhenSetOpenerPolicyThenWritesOpenerPolicy() {
this.writer.setPolicy(CrossOriginOpenerPolicyHeaderWriter.CrossOriginOpenerPolicy.SAME_ORIGIN_ALLOW_POPUPS);
this.writer.writeHeaders(this.request, this.response);
assertThat(this.response.getHeaderNames()).hasSize(1);
assertThat(this.response.getHeader(OPENER_HEADER_NAME)).isEqualTo("same-origin-allow-popups");
}
}

View File

@ -0,0 +1,80 @@
/*
* Copyright 2002-2021 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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.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;
class CrossOriginResourcePolicyHeaderWriterTests {
private static final String RESOURCE_HEADER_NAME = "Cross-Origin-Resource-Policy";
private CrossOriginResourcePolicyHeaderWriter writer;
private MockHttpServletRequest request;
private MockHttpServletResponse response;
@BeforeEach
void setup() {
this.writer = new CrossOriginResourcePolicyHeaderWriter();
this.request = new MockHttpServletRequest();
this.response = new MockHttpServletResponse();
}
@Test
void setResourcePolicyWhenNullThenThrowsIllegalArgument() {
assertThatIllegalArgumentException().isThrownBy(() -> this.writer.setPolicy(null))
.withMessage("resourcePolicy cannot be null");
}
@Test
void writeHeadersWhenDefaultValuesThenDontWriteHeaders() {
this.writer.writeHeaders(this.request, this.response);
assertThat(this.response.getHeaderNames()).hasSize(0);
}
@Test
void writeHeadersWhenResponseHeaderExistsThenDontOverride() {
this.response.addHeader(RESOURCE_HEADER_NAME, "same-site");
this.writer.setPolicy(CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy.CROSS_ORIGIN);
this.writer.writeHeaders(this.request, this.response);
assertThat(this.response.getHeader(RESOURCE_HEADER_NAME)).isEqualTo("same-site");
}
@Test
void writeHeadersWhenSetHeaderValuesThenWrites() {
this.writer.setPolicy(CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy.SAME_ORIGIN);
this.writer.writeHeaders(this.request, this.response);
assertThat(this.response.getHeader(RESOURCE_HEADER_NAME)).isEqualTo("same-origin");
}
@Test
void writeHeadersWhenSetResourcePolicyThenWritesResourcePolicy() {
this.writer.setPolicy(CrossOriginResourcePolicyHeaderWriter.CrossOriginResourcePolicy.SAME_SITE);
this.writer.writeHeaders(this.request, this.response);
assertThat(this.response.getHeaderNames()).hasSize(1);
assertThat(this.response.getHeader(RESOURCE_HEADER_NAME)).isEqualTo("same-site");
}
}

View File

@ -0,0 +1,76 @@
/*
* Copyright 2002-2021 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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.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;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
class CrossOriginEmbedderPolicyServerHttpHeadersWriterTests {
private ServerWebExchange exchange;
private CrossOriginEmbedderPolicyServerHttpHeadersWriter writer;
@BeforeEach
void setup() {
this.exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/"));
this.writer = new CrossOriginEmbedderPolicyServerHttpHeadersWriter();
}
@Test
void setEmbedderPolicyWhenNullEmbedderPolicyThenThrowsIllegalArgument() {
assertThatIllegalArgumentException().isThrownBy(() -> this.writer.setPolicy(null))
.withMessage("embedderPolicy cannot be null");
}
@Test
void writeHeadersWhenNoValuesThenDoesNotWriteHeaders() {
this.writer.writeHttpHeaders(this.exchange);
HttpHeaders headers = this.exchange.getResponse().getHeaders();
assertThat(headers).isEmpty();
}
@Test
void writeHeadersWhenResponseHeaderExistsThenDontOverride() {
this.exchange.getResponse().getHeaders().add(CrossOriginEmbedderPolicyServerHttpHeadersWriter.EMBEDDER_POLICY,
"require-corp");
this.writer.writeHttpHeaders(this.exchange);
HttpHeaders headers = this.exchange.getResponse().getHeaders();
assertThat(headers).hasSize(1);
assertThat(headers.get(CrossOriginEmbedderPolicyServerHttpHeadersWriter.EMBEDDER_POLICY))
.containsOnly("require-corp");
}
@Test
void writeHeadersWhenSetHeaderValuesThenWrites() {
this.writer.setPolicy(CrossOriginEmbedderPolicyServerHttpHeadersWriter.CrossOriginEmbedderPolicy.REQUIRE_CORP);
this.writer.writeHttpHeaders(this.exchange);
HttpHeaders headers = this.exchange.getResponse().getHeaders();
assertThat(headers).hasSize(1);
assertThat(headers.get(CrossOriginEmbedderPolicyServerHttpHeadersWriter.EMBEDDER_POLICY))
.containsOnly("require-corp");
}
}

View File

@ -0,0 +1,77 @@
/*
* Copyright 2002-2021 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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.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;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
class CrossOriginOpenerPolicyServerHttpHeadersWriterTests {
private ServerWebExchange exchange;
private CrossOriginOpenerPolicyServerHttpHeadersWriter writer;
@BeforeEach
void setup() {
this.exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/"));
this.writer = new CrossOriginOpenerPolicyServerHttpHeadersWriter();
}
@Test
void setOpenerPolicyWhenNullOpenerPolicyThenThrowsIllegalArgument() {
assertThatIllegalArgumentException().isThrownBy(() -> this.writer.setPolicy(null))
.withMessage("openerPolicy cannot be null");
}
@Test
void writeHeadersWhenNoValuesThenDoesNotWriteHeaders() {
this.writer.writeHttpHeaders(this.exchange);
HttpHeaders headers = this.exchange.getResponse().getHeaders();
assertThat(headers).isEmpty();
}
@Test
void writeHeadersWhenResponseHeaderExistsThenDontOverride() {
this.exchange.getResponse().getHeaders().add(CrossOriginOpenerPolicyServerHttpHeadersWriter.OPENER_POLICY,
"same-origin");
this.writer.writeHttpHeaders(this.exchange);
HttpHeaders headers = this.exchange.getResponse().getHeaders();
assertThat(headers).hasSize(1);
assertThat(headers.get(CrossOriginOpenerPolicyServerHttpHeadersWriter.OPENER_POLICY))
.containsOnly("same-origin");
}
@Test
void writeHeadersWhenSetHeaderValuesThenWrites() {
this.writer.setPolicy(
CrossOriginOpenerPolicyServerHttpHeadersWriter.CrossOriginOpenerPolicy.SAME_ORIGIN_ALLOW_POPUPS);
this.writer.writeHttpHeaders(this.exchange);
HttpHeaders headers = this.exchange.getResponse().getHeaders();
assertThat(headers).hasSize(1);
assertThat(headers.get(CrossOriginOpenerPolicyServerHttpHeadersWriter.OPENER_POLICY))
.containsOnly("same-origin-allow-popups");
}
}

View File

@ -0,0 +1,76 @@
/*
* Copyright 2002-2021 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.jupiter.api.BeforeEach;
import org.junit.jupiter.api.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;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
class CrossOriginResourcePolicyServerHttpHeadersWriterTests {
private ServerWebExchange exchange;
private CrossOriginResourcePolicyServerHttpHeadersWriter writer;
@BeforeEach
void setup() {
this.exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/"));
this.writer = new CrossOriginResourcePolicyServerHttpHeadersWriter();
}
@Test
void setResourcePolicyWhenNullThenThrowsIllegalArgument() {
assertThatIllegalArgumentException().isThrownBy(() -> this.writer.setPolicy(null))
.withMessage("resourcePolicy cannot be null");
}
@Test
void writeHeadersWhenNoValuesThenDoesNotWriteHeaders() {
this.writer.writeHttpHeaders(this.exchange);
HttpHeaders headers = this.exchange.getResponse().getHeaders();
assertThat(headers).isEmpty();
}
@Test
void writeHeadersWhenResponseHeaderExistsThenDontOverride() {
this.exchange.getResponse().getHeaders().add(CrossOriginResourcePolicyServerHttpHeadersWriter.RESOURCE_POLICY,
"same-origin");
this.writer.writeHttpHeaders(this.exchange);
HttpHeaders headers = this.exchange.getResponse().getHeaders();
assertThat(headers).hasSize(1);
assertThat(headers.get(CrossOriginResourcePolicyServerHttpHeadersWriter.RESOURCE_POLICY))
.containsOnly("same-origin");
}
@Test
void writeHeadersWhenSetHeaderValuesThenWrites() {
this.writer.setPolicy(CrossOriginResourcePolicyServerHttpHeadersWriter.CrossOriginResourcePolicy.SAME_ORIGIN);
this.writer.writeHttpHeaders(this.exchange);
HttpHeaders headers = this.exchange.getResponse().getHeaders();
assertThat(headers).hasSize(1);
assertThat(headers.get(CrossOriginResourcePolicyServerHttpHeadersWriter.RESOURCE_POLICY))
.containsOnly("same-origin");
}
}