Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support comma-delimited list of origin patterns in @CrossOrigin #27606

Closed
wants to merge 41 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
f1c24f0
supports multiple origin pattern injection under @crossorigin annotation
funky-eyes Oct 25, 2021
b2cd958
bugfix
funky-eyes Oct 25, 2021
b566145
bugfix
funky-eyes Oct 25, 2021
021850c
optimize
funky-eyes Oct 25, 2021
49efa2d
optimize
funky-eyes Oct 25, 2021
760a183
optimize
funky-eyes Oct 25, 2021
e0ed1bb
optimize
funky-eyes Oct 25, 2021
d4c48df
optimize
funky-eyes Oct 25, 2021
b025bc5
increases indicate that
funky-eyes Oct 25, 2021
aa47fed
bugfix
funky-eyes Oct 25, 2021
2a9a5a3
fix code style
funky-eyes Oct 25, 2021
0636694
bugfix
funky-eyes Oct 25, 2021
e6232c3
add test case
funky-eyes Oct 27, 2021
ee5f307
add test case
funky-eyes Oct 27, 2021
82dfc25
add test case
funky-eyes Oct 27, 2021
be49427
optimize
funky-eyes Oct 27, 2021
507a7b3
optimize
funky-eyes Oct 27, 2021
9fb78fd
rewriting code
funky-eyes Feb 9, 2022
9d77816
bugfix
funky-eyes Feb 9, 2022
576893f
bugfix
funky-eyes Feb 9, 2022
a6fc5f1
bugfix
funky-eyes Feb 9, 2022
cf3e7c9
bugfix
funky-eyes Feb 9, 2022
62aea3c
code formatting
funky-eyes Feb 9, 2022
6dc9544
bugfix
funky-eyes Feb 9, 2022
7c95b91
add test case
funky-eyes Feb 9, 2022
2e19b9e
Merge branch 'main' of github.com:spring-projects/spring-framework in…
funky-eyes Feb 9, 2022
24cd4b6
add test case
funky-eyes Feb 9, 2022
d033572
optimized code
funky-eyes Feb 9, 2022
8fc86bd
code formatting
funky-eyes Feb 10, 2022
3757215
code formatting
funky-eyes Feb 10, 2022
757cc83
optimize
funky-eyes Feb 10, 2022
92b0e74
optimize
funky-eyes Feb 10, 2022
592dec6
modify author
funky-eyes Feb 10, 2022
d40a83c
modify author
funky-eyes Feb 10, 2022
dd6ad8a
modify author
funky-eyes Feb 10, 2022
d0479e4
optimized code
funky-eyes Feb 10, 2022
1d07254
Merge branch '1025' of github.com:a364176773/spring-framework into 1025
funky-eyes Feb 10, 2022
d2fc3e9
optimized code
funky-eyes Feb 10, 2022
acc7547
restart
funky-eyes Feb 10, 2022
fcb73af
fix try
funky-eyes Feb 10, 2022
eca7cc2
remove org.junit.jupiter.api.Assertions
funky-eyes Feb 10, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package org.springframework.beans.factory.config;

import java.util.Arrays;

import org.springframework.lang.Nullable;
import org.springframework.util.StringValueResolver;

Expand All @@ -29,6 +31,7 @@
* with no scope specified for any contextual objects to access.
*
* @author Juergen Hoeller
* @author Chen Jianbin
* @since 4.3
* @see ConfigurableBeanFactory#resolveEmbeddedValue(String)
* @see ConfigurableBeanFactory#getBeanExpressionResolver()
Expand All @@ -54,7 +57,15 @@ public String resolveStringValue(String strVal) {
String value = this.exprContext.getBeanFactory().resolveEmbeddedValue(strVal);
if (this.exprResolver != null && value != null) {
Object evaluated = this.exprResolver.evaluate(value, this.exprContext);
value = (evaluated != null ? evaluated.toString() : null);
if (evaluated != null) {
if (evaluated instanceof String[]) {
String str = Arrays.toString((String[])evaluated);
value = str.substring(1, str.length() - 1);
}
else {
value = evaluated.toString();
}
}
}
return value;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

package org.springframework.context;

import java.util.Arrays;
import java.util.Set;

import org.springframework.beans.factory.Aware;
import org.springframework.util.StringValueResolver;

Expand All @@ -28,6 +31,7 @@
*
* @author Juergen Hoeller
* @author Chris Beams
* @author Jianbin Chen
* @since 3.0.3
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#resolveEmbeddedValue(String)
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory#getBeanExpressionResolver()
Expand All @@ -40,4 +44,36 @@ public interface EmbeddedValueResolverAware extends Aware {
*/
void setEmbeddedValueResolver(StringValueResolver resolver);

/**
* resolve Origin Or Pattern Value.
* @param origin origin
* @param origins origins
*/
default void resolveOriginOrPatternValue(String origin, Set<String> origins) {
int bracketIndex = origin.indexOf("[");
int commaIndex = origin.indexOf(",");
int lastIndex = origin.lastIndexOf(",");
if (lastIndex != commaIndex) {
if (bracketIndex < commaIndex) {
int index = origin.indexOf("]");
origins.add(origin.substring(0, ++index));
origin = origin.substring(++index);
}
else {
int index = origin.indexOf(",");
String value = origin.substring(0, ++index);
origins.add(value.substring(0, value.length() - 1));
origin = origin.substring(origin.indexOf(",") + 1);
}
resolveOriginOrPatternValue(origin, origins);
}
else {
if (bracketIndex == -1) {
origins.addAll(Arrays.asList(origin.split(",")));
}
else {
origins.add(origin);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;

import org.springframework.context.EmbeddedValueResolverAware;
Expand Down Expand Up @@ -54,6 +56,7 @@
*
* @author Rossen Stoyanchev
* @author Sam Brannen
* @author Chen Jianbin
* @since 5.0
*/
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
Expand Down Expand Up @@ -313,10 +316,18 @@ private void updateCorsConfig(CorsConfiguration config, @Nullable CrossOrigin an
return;
}
for (String origin : annotation.origins()) {
config.addAllowedOrigin(resolveCorsAnnotationValue(origin));
Set<String> origins = new HashSet<>();
resolveOriginOrPatternValue(resolveCorsAnnotationValue(origin), origins);
for (String org : origins) {
config.addAllowedOrigin(org);
}
}
for (String patterns : annotation.originPatterns()) {
config.addAllowedOriginPattern(resolveCorsAnnotationValue(patterns));
for (String pattern : annotation.originPatterns()) {
Set<String> patterns = new HashSet<>();
resolveOriginOrPatternValue(resolveCorsAnnotationValue(pattern), patterns);
for (String pat : patterns) {
config.addAllowedOriginPattern(pat);
}
}
for (RequestMethod method : annotation.methods()) {
config.addAllowedMethod(method.name());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
* @author Sebastien Deleuze
* @author Rossen Stoyanchev
* @author Sam Brannen
* @author Chen Jianbin
*/
class CrossOriginAnnotationIntegrationTests extends AbstractRequestMappingIntegrationTests {

Expand All @@ -67,8 +68,8 @@ protected ApplicationContext initApplicationContext() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(WebConfig.class);
Properties props = new Properties();
props.setProperty("myOrigin", "https://site1.com");
props.setProperty("myOriginPattern", "https://*.com");
props.setProperty("myOrigin", "https://site1.com,https://site2.com");
props.setProperty("myOriginPattern", "https://*.com,https://*.cn,https://*.cn:8088,https://*.com:[8089,8088]");
context.getEnvironment().getPropertySources().addFirst(new PropertiesPropertySource("ps", props));
context.register(PropertySourcesPlaceholderConfigurer.class);
context.refresh();
Expand Down Expand Up @@ -205,6 +206,12 @@ void customOriginDefinedViaPlaceholder(HttpServer httpServer) throws Exception {
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getHeaders().getAccessControlAllowOrigin()).isEqualTo("https://site1.com");
assertThat(entity.getBody()).isEqualTo("placeholder");
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setOrigin("https://site2.com");
ResponseEntity<String> entity2 = performGet("/origin-placeholder", httpHeaders, String.class);
assertThat(entity2.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity2.getHeaders().getAccessControlAllowOrigin()).isEqualTo("https://site2.com");
assertThat(entity2.getBody()).isEqualTo("placeholder");
}

@ParameterizedHttpServerTest
Expand All @@ -225,6 +232,17 @@ void customOriginPatternDefinedViaPlaceholder(HttpServer httpServer) throws Exce
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity.getHeaders().getAccessControlAllowOrigin()).isEqualTo("https://site1.com");
assertThat(entity.getBody()).isEqualTo("pattern-placeholder");
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setOrigin("https://site1.cn");
ResponseEntity<String> entity2 = performGet("/origin-pattern-placeholder", httpHeaders, String.class);
assertThat(entity2.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity2.getHeaders().getAccessControlAllowOrigin()).isEqualTo("https://site1.cn");
assertThat(entity2.getBody()).isEqualTo("pattern-placeholder");
httpHeaders.setOrigin("https://site1.com:8089");
ResponseEntity<String> entity3 = performGet("/origin-pattern-placeholder", httpHeaders, String.class);
assertThat(entity3.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(entity3.getHeaders().getAccessControlAllowOrigin()).isEqualTo("https://site1.com:8089");
assertThat(entity3.getBody()).isEqualTo("pattern-placeholder");
}

@ParameterizedHttpServerTest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;

import jakarta.servlet.http.HttpServletRequest;
Expand Down Expand Up @@ -71,6 +73,7 @@
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @author Sam Brannen
* @author Chen Jianbin
* @since 3.1
*/
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
Expand Down Expand Up @@ -473,10 +476,18 @@ private void updateCorsConfig(CorsConfiguration config, @Nullable CrossOrigin an
return;
}
for (String origin : annotation.origins()) {
config.addAllowedOrigin(resolveCorsAnnotationValue(origin));
Set<String> origins = new HashSet<>();
resolveOriginOrPatternValue(resolveCorsAnnotationValue(origin), origins);
for (String org : origins) {
config.addAllowedOrigin(org);
}
}
for (String patterns : annotation.originPatterns()) {
config.addAllowedOriginPattern(resolveCorsAnnotationValue(patterns));
for (String pattern : annotation.originPatterns()) {
Set<String> patterns = new HashSet<>();
resolveOriginOrPatternValue(resolveCorsAnnotationValue(pattern), patterns);
for (String pat : patterns) {
config.addAllowedOriginPattern(pat);
}
}
for (RequestMethod method : annotation.methods()) {
config.addAllowedMethod(method.name());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Objects;
import java.util.Properties;
import java.util.stream.Stream;

Expand Down Expand Up @@ -64,15 +65,16 @@
* @author Sam Brannen
* @author Nicolas Labrot
* @author Rossen Stoyanchev
* @author Chen Jianbin
*/
class CrossOriginTests {

@SuppressWarnings("unused")
static Stream<TestRequestMappingInfoHandlerMapping> pathPatternsArguments() {
StaticWebApplicationContext wac = new StaticWebApplicationContext();
Properties props = new Properties();
props.setProperty("myOrigin", "https://example.com");
props.setProperty("myDomainPattern", "http://*.example.com");
props.setProperty("myOrigin", "https://example.com,https://example.cn");
props.setProperty("myDomainPattern", "http://*.example.com,http://*.example.cn");
wac.getEnvironment().getPropertySources().addFirst(new PropertiesPropertySource("ps", props));
wac.registerSingleton("ppc", PropertySourcesPlaceholderConfigurer.class);
wac.refresh();
Expand Down Expand Up @@ -194,7 +196,8 @@ void customOriginDefinedViaPlaceholder(TestRequestMappingInfoHandlerMapping mapp
HandlerExecutionChain chain = mapping.getHandler(request);
CorsConfiguration config = getCorsConfiguration(chain, false);
assertThat(config).isNotNull();
assertThat(config.getAllowedOrigins()).isEqualTo(Collections.singletonList("https://example.com"));
assertThat(Objects.requireNonNull(config.getAllowedOrigins()).size()).isEqualTo(2);
assertThat(config.getAllowedOrigins().contains("https://example.com"));
assertThat(config.getAllowCredentials()).isNull();
}

Expand All @@ -218,7 +221,20 @@ public void customOriginPatternViaPlaceholder(TestRequestMappingInfoHandlerMappi
CorsConfiguration config = getCorsConfiguration(chain, false);
assertThat(config).isNotNull();
assertThat(config.getAllowedOrigins()).isNull();
assertThat(config.getAllowedOriginPatterns()).isEqualTo(Collections.singletonList("http://*.example.com"));
assertThat(config.getAllowedOriginPatterns().size()).isEqualTo(2);
assertThat(config.getAllowedOriginPatterns().contains("http://*.example.com")).isTrue();
assertThat(config.getAllowCredentials()).isNull();
}

@PathPatternsParameterizedTest
public void customMultiOriginPatternViaPlaceholder(TestRequestMappingInfoHandlerMapping mapping) throws Exception {
mapping.registerHandler(new MethodLevelController());
this.request.setRequestURI("/customMultiOriginPatternPlaceholder");
HandlerExecutionChain chain = mapping.getHandler(request);
CorsConfiguration config = getCorsConfiguration(chain, false);
assertThat(config).isNotNull();
assertThat(config.getAllowedOrigins()).isNull();
assertThat(config.getAllowedOriginPatterns().size()).isEqualTo(4);
assertThat(config.getAllowCredentials()).isNull();
}

Expand Down Expand Up @@ -477,8 +493,16 @@ public void customOriginPatternDefinedViaValueAttribute() {
@RequestMapping("/customOriginPatternPlaceholder")
public void customOriginPatternDefinedViaPlaceholder() {
}
}

@CrossOrigin(
originPatterns = {
"http://*.example.net,http://*.example.com:[8088,8089]",
"#{'${myDomainPattern}'.split(',')}"
})
@RequestMapping("/customMultiOriginPatternPlaceholder")
public void customMultiOriginPatternDefinedViaPlaceholder() {
}
}

@Controller
@SuppressWarnings("unused")
Expand Down