Browse Source

CorsConfiguration supports port pattern and port lists

See gh-26927
pull/26951/head
Ruslan Akhundov 5 years ago committed by Rossen Stoyanchev
parent
commit
66588bae92
  1. 24
      spring-web/src/main/java/org/springframework/web/cors/CorsConfiguration.java
  2. 12
      spring-web/src/test/java/org/springframework/web/cors/CorsConfigurationTests.java

24
spring-web/src/main/java/org/springframework/web/cors/CorsConfiguration.java

@ -23,6 +23,7 @@ import java.util.Collections; @@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@ -176,7 +177,9 @@ public class CorsConfiguration { @@ -176,7 +177,9 @@ public class CorsConfiguration {
* it always sets the {@code Access-Control-Allow-Origin} response header to
* the matched origin and never to {@code "*"}, nor to any other pattern, and
* therefore can be used in combination with {@link #setAllowCredentials}
* set to {@code true}.
* set to {@code true}. Patterns also support list of allowed ports for origin,
* e.g. {@code "https://*.domain1.com:[8080,8081]"}. Additionally wildcard is supported
* in case any generic port should be allowed {@code "https://*.domain1.com:[*]"}.
* <p>By default this is not set.
* @since 5.3
*/
@ -647,6 +650,8 @@ public class CorsConfiguration { @@ -647,6 +650,8 @@ public class CorsConfiguration {
*/
private static class OriginPattern {
private static final Pattern PORT_LIST_PATTERN = Pattern.compile("(.*):\\[(\\*|[\\d,]+)]");
private final String declaredPattern;
private final Pattern pattern;
@ -657,8 +662,25 @@ public class CorsConfiguration { @@ -657,8 +662,25 @@ public class CorsConfiguration {
}
private static Pattern toPattern(String patternValue) {
//if pattern ends with allowed ports list
Matcher matcher = PORT_LIST_PATTERN.matcher(patternValue);
String portList = null;
if (matcher.matches()) {
patternValue = matcher.group(1);
portList = matcher.group(2);
}
patternValue = "\\Q" + patternValue + "\\E";
patternValue = patternValue.replace("*", "\\E.*\\Q");
if (ALL.equals(portList)) {
//there is a corner case. If '*' is specified, then origins with implicit default port (e.g. "https://test.com") should also match.
patternValue += "(:\\d+)?";
}
else if (portList != null) {
patternValue += ":(" + portList.replace(',', '|') + ")";
}
return Pattern.compile(patternValue);
}

12
spring-web/src/test/java/org/springframework/web/cors/CorsConfigurationTests.java

@ -335,6 +335,15 @@ public class CorsConfigurationTests { @@ -335,6 +335,15 @@ public class CorsConfigurationTests {
config.addAllowedOriginPattern("https://*.domain.com");
assertThat(config.checkOrigin("https://example.domain.com")).isEqualTo("https://example.domain.com");
config.addAllowedOriginPattern("https://*.port.domain.com:[*]");
assertThat(config.checkOrigin("https://example.port.domain.com")).isEqualTo("https://example.port.domain.com");
assertThat(config.checkOrigin("https://example.port.domain.com:1234")).isEqualTo("https://example.port.domain.com:1234");
config.addAllowedOriginPattern("https://*.specific.port.com:[8080,8081]");
assertThat(config.checkOrigin("https://example.specific.port.com:8080")).isEqualTo("https://example.specific.port.com:8080");
assertThat(config.checkOrigin("https://example.specific.port.com:8081")).isEqualTo("https://example.specific.port.com:8081");
assertThat(config.checkOrigin("https://example.specific.port.com:1234")).isNull();
config.setAllowCredentials(false);
assertThat(config.checkOrigin("https://example.domain.com")).isEqualTo("https://example.domain.com");
}
@ -352,6 +361,9 @@ public class CorsConfigurationTests { @@ -352,6 +361,9 @@ public class CorsConfigurationTests {
config.setAllowedOriginPatterns(new ArrayList<>());
assertThat(config.checkOrigin("https://domain.com")).isNull();
config.setAllowedOriginPatterns(Collections.singletonList("https://*.specific.port.com:[8080,8081]"));
assertThat(config.checkOrigin("https://example.specific.port.com:1234")).isNull();
}
@Test

Loading…
Cancel
Save