Updates to CORS patterns contribution
Closes gh-25016
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -18,6 +18,7 @@ package org.springframework.web.reactive.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
|
||||
@@ -44,24 +45,28 @@ public class CorsRegistration {
|
||||
|
||||
|
||||
/**
|
||||
* The list of allowed origins that be specific origins, e.g.
|
||||
* {@code "https://domain1.com"}, or {@code "*"} for all origins.
|
||||
* <p>A matched origin is listed in the {@code Access-Control-Allow-Origin}
|
||||
* response header of preflight actual CORS requests.
|
||||
* <p>By default all origins are allowed.
|
||||
* <p><strong>Note:</strong> CORS checks use values from "Forwarded"
|
||||
* (<a href="https://tools.ietf.org/html/rfc7239">RFC 7239</a>),
|
||||
* "X-Forwarded-Host", "X-Forwarded-Port", and "X-Forwarded-Proto" headers,
|
||||
* if present, in order to reflect the client-originated address.
|
||||
* Consider using the {@code ForwardedHeaderFilter} in order to choose from a
|
||||
* central place whether to extract and use, or to discard such headers.
|
||||
* See the Spring Framework reference for more on this filter.
|
||||
* A list of origins for which cross-origin requests are allowed. Please,
|
||||
* see {@link CorsConfiguration#setAllowedOrigins(List)} for details.
|
||||
* <p>By default all origins are allowed unless {@code originPatterns} is
|
||||
* also set in which case {@code originPatterns} is used instead.
|
||||
*/
|
||||
public CorsRegistration allowedOrigins(String... origins) {
|
||||
this.config.setAllowedOrigins(new ArrayList<>(Arrays.asList(origins)));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternative to {@link #allowCredentials} that supports origins declared
|
||||
* via wildcard patterns. Please, see
|
||||
* @link CorsConfiguration#setAllowedOriginPatterns(List)} for details.
|
||||
* <p>By default this is not set.
|
||||
* @since 5.3
|
||||
*/
|
||||
public CorsRegistration allowedOriginPatterns(String... patterns) {
|
||||
this.config.setAllowedOriginPatterns(Arrays.asList(patterns));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the HTTP methods to allow, e.g. {@code "GET"}, {@code "POST"}, etc.
|
||||
* <p>The special value {@code "*"} allows all methods.
|
||||
|
||||
@@ -187,6 +187,9 @@ public abstract class AbstractHandlerMapping extends ApplicationObjectSupport
|
||||
CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(exchange) : null);
|
||||
CorsConfiguration handlerConfig = getCorsConfiguration(handler, exchange);
|
||||
config = (config != null ? config.combine(handlerConfig) : handlerConfig);
|
||||
if (config != null) {
|
||||
config.validateAllowCredentials();
|
||||
}
|
||||
if (!this.corsProcessor.process(config, exchange) || CorsUtils.isPreFlightRequest(request)) {
|
||||
return REQUEST_HANDLED_HANDLER;
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
private static final CorsConfiguration ALLOW_CORS_CONFIG = new CorsConfiguration();
|
||||
|
||||
static {
|
||||
ALLOW_CORS_CONFIG.addAllowedOrigin("*");
|
||||
ALLOW_CORS_CONFIG.addAllowedOriginPattern("*");
|
||||
ALLOW_CORS_CONFIG.addAllowedMethod("*");
|
||||
ALLOW_CORS_CONFIG.addAllowedHeader("*");
|
||||
ALLOW_CORS_CONFIG.setAllowCredentials(true);
|
||||
@@ -485,9 +485,10 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
|
||||
validateMethodMapping(handlerMethod, mapping);
|
||||
this.mappingLookup.put(mapping, handlerMethod);
|
||||
|
||||
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
|
||||
if (corsConfig != null) {
|
||||
this.corsLookup.put(handlerMethod, corsConfig);
|
||||
CorsConfiguration config = initCorsConfiguration(handler, method, mapping);
|
||||
if (config != null) {
|
||||
config.validateAllowCredentials();
|
||||
this.corsLookup.put(handlerMethod, config);
|
||||
}
|
||||
|
||||
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
* Copyright 2002-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.web.reactive.config;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -56,11 +57,20 @@ public class CorsRegistryTests {
|
||||
assertThat(configs.size()).isEqualTo(1);
|
||||
CorsConfiguration config = configs.get("/foo");
|
||||
assertThat(config.getAllowedOrigins()).isEqualTo(Arrays.asList("https://domain2.com", "https://domain2.com"));
|
||||
assertThat(config.getAllowedMethods()).isEqualTo(Arrays.asList("DELETE"));
|
||||
assertThat(config.getAllowedMethods()).isEqualTo(Collections.singletonList("DELETE"));
|
||||
assertThat(config.getAllowedHeaders()).isEqualTo(Arrays.asList("header1", "header2"));
|
||||
assertThat(config.getExposedHeaders()).isEqualTo(Arrays.asList("header3", "header4"));
|
||||
assertThat(config.getAllowCredentials()).isEqualTo(false);
|
||||
assertThat(config.getMaxAge()).isEqualTo(Long.valueOf(3600));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void allowCredentials() {
|
||||
this.registry.addMapping("/foo").allowCredentials(true);
|
||||
CorsConfiguration config = this.registry.getCorsConfigurations().get("/foo");
|
||||
assertThat(config.getAllowedOrigins())
|
||||
.as("Globally origins=\"*\" and allowCredentials=true should be possible")
|
||||
.containsExactly("*");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ public class CorsUrlHandlerMappingTests {
|
||||
@Test
|
||||
public void actualRequestWithGlobalPatternCorsConfig() throws Exception {
|
||||
CorsConfiguration mappedConfig = new CorsConfiguration();
|
||||
mappedConfig.addAllowedOriginPattern(".*\\.domain2.com");
|
||||
mappedConfig.addAllowedOriginPattern("https://*.domain2.com");
|
||||
this.handlerMapping.setCorsConfigurations(Collections.singletonMap("/welcome.html", mappedConfig));
|
||||
|
||||
String origin = "https://example.domain2.com";
|
||||
@@ -122,7 +122,8 @@ public class CorsUrlHandlerMappingTests {
|
||||
|
||||
assertThat(actual).isNotNull();
|
||||
assertThat(actual).isSameAs(this.welcomeController);
|
||||
assertThat(exchange.getResponse().getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)).isEqualTo("https://example.domain2.com");
|
||||
assertThat(exchange.getResponse().getHeaders().getFirst(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN))
|
||||
.isEqualTo("https://example.domain2.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -197,7 +198,7 @@ public class CorsUrlHandlerMappingTests {
|
||||
@Override
|
||||
public CorsConfiguration getCorsConfiguration(ServerWebExchange exchange) {
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
config.addAllowedOrigin("*");
|
||||
config.addAllowedOriginPattern("*");
|
||||
config.setAllowCredentials(true);
|
||||
return config;
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ class CrossOriginAnnotationIntegrationTests extends AbstractRequestMappingIntegr
|
||||
context.register(WebConfig.class);
|
||||
Properties props = new Properties();
|
||||
props.setProperty("myOrigin", "https://site1.com");
|
||||
props.setProperty("myOriginPattern", ".*\\.com");
|
||||
props.setProperty("myOriginPattern", "https://*.com");
|
||||
context.getEnvironment().getPropertySources().addFirst(new PropertiesPropertySource("ps", props));
|
||||
context.register(PropertySourcesPlaceholderConfigurer.class);
|
||||
context.refresh();
|
||||
@@ -358,7 +358,7 @@ class CrossOriginAnnotationIntegrationTests extends AbstractRequestMappingIntegr
|
||||
return "placeholder";
|
||||
}
|
||||
|
||||
@CrossOrigin(originPatterns = ".*\\.com")
|
||||
@CrossOrigin(originPatterns = "https://*.com")
|
||||
@GetMapping("/origin-pattern-value-attribute")
|
||||
public String customOriginPatternDefinedViaValueAttribute() {
|
||||
return "pattern-value-attribute";
|
||||
@@ -388,7 +388,7 @@ class CrossOriginAnnotationIntegrationTests extends AbstractRequestMappingIntegr
|
||||
return "bar";
|
||||
}
|
||||
|
||||
@CrossOrigin(allowCredentials = "true")
|
||||
@CrossOrigin(originPatterns = "*", allowCredentials = "true")
|
||||
@GetMapping("/baz")
|
||||
public String baz() {
|
||||
return "baz";
|
||||
|
||||
@@ -161,8 +161,7 @@ class GlobalCorsConfigIntegrationTests extends AbstractRequestMappingIntegration
|
||||
ResponseEntity<String> entity = performOptions("/ambiguous", this.headers, String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getHeaders().getAccessControlAllowOrigin()).isEqualTo("http://localhost:9000");
|
||||
assertThat(entity.getHeaders().getAccessControlAllowMethods())
|
||||
.containsExactly(HttpMethod.GET);
|
||||
assertThat(entity.getHeaders().getAccessControlAllowMethods()).containsExactly(HttpMethod.GET);
|
||||
assertThat(entity.getHeaders().getAccessControlAllowCredentials()).isEqualTo(true);
|
||||
assertThat(entity.getHeaders().get(HttpHeaders.VARY))
|
||||
.containsExactly(HttpHeaders.ORIGIN, HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD,
|
||||
@@ -177,12 +176,9 @@ class GlobalCorsConfigIntegrationTests extends AbstractRequestMappingIntegration
|
||||
|
||||
@Override
|
||||
protected void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/cors-restricted")
|
||||
.allowedOrigins("https://foo")
|
||||
.allowedMethods("GET", "POST");
|
||||
registry.addMapping("/cors-restricted").allowedOrigins("https://foo").allowedMethods("GET", "POST");
|
||||
registry.addMapping("/cors");
|
||||
registry.addMapping("/ambiguous")
|
||||
.allowedMethods("GET", "POST");
|
||||
registry.addMapping("/ambiguous").allowedMethods("GET", "POST");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user