Skip to content

Commit b095c77

Browse files
committed
Polish "Add config prop for endpoints' CORS allowed origin patterns"
See gh-24680
1 parent d7f891b commit b095c77

File tree

3 files changed

+35
-55
lines changed

3 files changed

+35
-55
lines changed

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

Lines changed: 9 additions & 6 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,15 +37,18 @@
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. When credentials are supported only explicit urls are
42-
* allowed.
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.
4344
*/
4445
private List<String> allowedOrigins = new ArrayList<>();
4546

4647
/**
47-
* Comma-separated list of origins patterns to allow. Must be used when credentials
48-
* are supported and do you want to use wildcard urls.
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.
4952
*/
5053
private List<String> allowedOriginPatterns = new ArrayList<>();
5154

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

Lines changed: 14 additions & 27 deletions
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.
@@ -16,9 +16,6 @@
1616

1717
package org.springframework.boot.actuate.autoconfigure.integrationtest;
1818

19-
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options;
20-
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
21-
2219
import java.util.function.Consumer;
2320

2421
import org.junit.jupiter.api.Test;
@@ -74,6 +71,19 @@ void settingAllowedOriginsEnablesCors() {
7471
}));
7572
}
7673

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+
7787
@Test
7888
void maxAgeDefaultsTo30Minutes() {
7989
this.contextRunner.withPropertyValues("management.endpoints.web.cors.allowed-origins:spring.example.org")
@@ -148,29 +158,6 @@ void credentialsCanBeDisabled() {
148158
.expectHeader().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)));
149159
}
150160

151-
@Test
152-
void settingAllowedOriginsPattern() {
153-
this.contextRunner
154-
.withPropertyValues("management.endpoints.web.cors.allowed-origin-patterns:*.example.com",
155-
"management.endpoints.web.cors.allow-credentials:true")
156-
.run(withWebTestClient((webTestClient) -> webTestClient.options().uri("/actuator/beans")
157-
.header("Origin", "spring.example.com")
158-
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "HEAD").exchange().expectStatus().isOk()
159-
.expectHeader().valueEquals(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET,HEAD")));
160-
}
161-
162-
@Test
163-
void requestsWithDisallowedOriginPatternsAreRejected() {
164-
this.contextRunner
165-
.withPropertyValues("management.endpoints.web.cors.allowed-origin-patterns:*.example.com",
166-
"management.endpoints.web.cors.allow-credentials:true")
167-
.run(withWebTestClient((webTestClient) -> webTestClient.options().uri("/actuator/beans")
168-
.header("Origin", "spring.example.org")
169-
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "HEAD").exchange().expectStatus()
170-
.isForbidden()));
171-
172-
}
173-
174161
private ContextConsumer<ReactiveWebApplicationContext> withWebTestClient(Consumer<WebTestClient> webTestClient) {
175162
return (context) -> webTestClient.accept(WebTestClient.bindToApplicationContext(context).configureClient()
176163
.baseUrl("https://spring.example.org").build());

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

Lines changed: 12 additions & 22 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.
@@ -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")
@@ -156,27 +167,6 @@ void credentialsCanBeDisabled() {
156167
.andExpect(header().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS))));
157168
}
158169

159-
@Test
160-
void settingAllowedOriginsPattern() {
161-
this.contextRunner.withPropertyValues("management.endpoints.web.cors.allowed-origin-patterns:*.example.com",
162-
"management.endpoints.web.cors.allow-credentials:true").run(withMockMvc((mockMvc) -> {
163-
mockMvc.perform(options("/actuator/beans").header("Origin", "bar.example.com")
164-
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET")).andExpect(status().isOk());
165-
performAcceptedCorsRequest(mockMvc);
166-
}));
167-
}
168-
169-
@Test
170-
void requestsWithDisallowedOriginPatternsAreRejected() {
171-
this.contextRunner.withPropertyValues("management.endpoints.web.cors.allowed-origin-patterns:*.example.com",
172-
"management.endpoints.web.cors.allow-credentials:true").run(withMockMvc((mockMvc) -> {
173-
mockMvc.perform(options("/actuator/beans").header("Origin", "bar.domain.com")
174-
.header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET"))
175-
.andExpect(status().isForbidden());
176-
performAcceptedCorsRequest(mockMvc);
177-
}));
178-
}
179-
180170
private ContextConsumer<WebApplicationContext> withMockMvc(MockMvcConsumer mockMvc) {
181171
return (context) -> mockMvc.accept(MockMvcBuilders.webAppContextSetup(context).build());
182172
}

0 commit comments

Comments
 (0)