Skip to content

Commit 847bb62

Browse files
committed
Merge pull request #24680 from pedivo
* gh-24680: Polish "Add config prop for endpoints' CORS allowed origin patterns" Add config prop for endpoints' CORS allowed origin patterns Closes gh-24680
2 parents 743343c + b095c77 commit 847bb62

File tree

3 files changed

+49
-6
lines changed

3 files changed

+49
-6
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/CorsEndpointProperties.java

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -37,11 +37,21 @@
3737
public class CorsEndpointProperties {
3838

3939
/**
40-
* Comma-separated list of origins to allow. '*' allows all origins. When not set,
41-
* CORS support is disabled.
40+
* Comma-separated list of origins to allow. '*' allows all origins. When credentials
41+
* are allowed, '*' cannot be used and origin patterns should be configured instead.
42+
* When no allowed origins or allowed origin patterns are set, CORS support is
43+
* disabled.
4244
*/
4345
private List<String> allowedOrigins = new ArrayList<>();
4446

47+
/**
48+
* Comma-separated list of origin patterns to allow. Unlike allowed origins which only
49+
* supports '*', origin patterns are more flexible (for example
50+
* 'https://*.example.com') and can be used when credentials are allowed. When no
51+
* allowed origin patterns or allowed origins are set, CORS support is disabled.
52+
*/
53+
private List<String> allowedOriginPatterns = new ArrayList<>();
54+
4555
/**
4656
* Comma-separated list of methods to allow. '*' allows all methods. When not set,
4757
* defaults to GET.
@@ -78,6 +88,14 @@ public void setAllowedOrigins(List<String> allowedOrigins) {
7888
this.allowedOrigins = allowedOrigins;
7989
}
8090

91+
public List<String> getAllowedOriginPatterns() {
92+
return this.allowedOriginPatterns;
93+
}
94+
95+
public void setAllowedOriginPatterns(List<String> allowedOriginPatterns) {
96+
this.allowedOriginPatterns = allowedOriginPatterns;
97+
}
98+
8199
public List<String> getAllowedMethods() {
82100
return this.allowedMethods;
83101
}
@@ -119,12 +137,13 @@ public void setMaxAge(Duration maxAge) {
119137
}
120138

121139
public CorsConfiguration toCorsConfiguration() {
122-
if (CollectionUtils.isEmpty(this.allowedOrigins)) {
140+
if (CollectionUtils.isEmpty(this.allowedOrigins) && CollectionUtils.isEmpty(this.allowedOriginPatterns)) {
123141
return null;
124142
}
125143
PropertyMapper map = PropertyMapper.get();
126144
CorsConfiguration configuration = new CorsConfiguration();
127145
map.from(this::getAllowedOrigins).to(configuration::setAllowedOrigins);
146+
map.from(this::getAllowedOriginPatterns).to(configuration::setAllowedOriginPatterns);
128147
map.from(this::getAllowedHeaders).whenNot(CollectionUtils::isEmpty).to(configuration::setAllowedHeaders);
129148
map.from(this::getAllowedMethods).whenNot(CollectionUtils::isEmpty).to(configuration::setAllowedMethods);
130149
map.from(this::getExposedHeaders).whenNot(CollectionUtils::isEmpty).to(configuration::setExposedHeaders);

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/WebFluxEndpointCorsIntegrationTests.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2020 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -71,6 +71,19 @@ void settingAllowedOriginsEnablesCors() {
7171
}));
7272
}
7373

74+
@Test
75+
void settingAllowedOriginPatternsEnablesCors() {
76+
this.contextRunner
77+
.withPropertyValues("management.endpoints.web.cors.allowed-origin-patterns:*.example.org",
78+
"management.endpoints.web.cors.allow-credentials:true")
79+
.run(withWebTestClient((webTestClient) -> {
80+
webTestClient.options().uri("/actuator/beans").header("Origin", "spring.example.com")
81+
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET").exchange().expectStatus()
82+
.isForbidden();
83+
performAcceptedCorsRequest(webTestClient, "/actuator/beans");
84+
}));
85+
}
86+
7487
@Test
7588
void maxAgeDefaultsTo30Minutes() {
7689
this.contextRunner.withPropertyValues("management.endpoints.web.cors.allowed-origins:spring.example.org")

spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/WebMvcEndpointCorsIntegrationTests.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2019 the original author or authors.
2+
* Copyright 2012-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -77,6 +77,17 @@ void settingAllowedOriginsEnablesCors() {
7777
}));
7878
}
7979

80+
@Test
81+
void settingAllowedOriginPatternsEnablesCors() {
82+
this.contextRunner.withPropertyValues("management.endpoints.web.cors.allowed-origin-patterns:*.example.com",
83+
"management.endpoints.web.cors.allow-credentials:true").run(withMockMvc((mockMvc) -> {
84+
mockMvc.perform(options("/actuator/beans").header("Origin", "bar.example.org")
85+
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET"))
86+
.andExpect(status().isForbidden());
87+
performAcceptedCorsRequest(mockMvc);
88+
}));
89+
}
90+
8091
@Test
8192
void maxAgeDefaultsTo30Minutes() {
8293
this.contextRunner.withPropertyValues("management.endpoints.web.cors.allowed-origins:foo.example.com")

0 commit comments

Comments
 (0)