Skip to content

Commit 0f8a819

Browse files
committed
Enable cors in default management security config
Fixes gh-9548
1 parent 2aa4ed2 commit 0f8a819

File tree

4 files changed

+96
-1
lines changed

4 files changed

+96
-1
lines changed

spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/ManagementWebSecurityAutoConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ protected void configure(HttpSecurity http) throws Exception {
222222
http.requestMatcher(matcher);
223223
// ... but permitAll() for the non-sensitive ones
224224
configurePermittedRequests(http.authorizeRequests());
225-
http.httpBasic().authenticationEntryPoint(entryPoint);
225+
http.httpBasic().authenticationEntryPoint(entryPoint).and().cors();
226226
// No cookies for management endpoints by default
227227
http.csrf().disable();
228228
http.sessionManagement()

spring-boot-samples/spring-boot-sample-actuator/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@
4141
<artifactId>spring-boot-starter-remote-shell</artifactId>
4242
</dependency>
4343
<!-- Runtime -->
44+
<dependency>
45+
<groupId>org.apache.httpcomponents</groupId>
46+
<artifactId>httpclient</artifactId>
47+
<scope>runtime</scope>
48+
</dependency>
4449
<dependency>
4550
<groupId>com.h2database</groupId>
4651
<artifactId>h2</artifactId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
package sample.actuator;
2+
3+
import java.net.URI;
4+
import java.util.Map;
5+
6+
import org.junit.Before;
7+
import org.junit.Test;
8+
import org.junit.runner.RunWith;
9+
10+
import org.springframework.beans.factory.annotation.Autowired;
11+
import org.springframework.boot.test.context.SpringBootTest;
12+
import org.springframework.boot.test.web.client.LocalHostUriTemplateHandler;
13+
import org.springframework.boot.test.web.client.TestRestTemplate;
14+
import org.springframework.context.ApplicationContext;
15+
import org.springframework.http.HttpStatus;
16+
import org.springframework.http.RequestEntity;
17+
import org.springframework.http.ResponseEntity;
18+
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
19+
import org.springframework.test.annotation.DirtiesContext;
20+
import org.springframework.test.context.ActiveProfiles;
21+
import org.springframework.test.context.junit4.SpringRunner;
22+
import org.springframework.web.client.RestTemplate;
23+
24+
import static org.assertj.core.api.Assertions.assertThat;
25+
26+
/**
27+
* Integration test for cors preflight requests to management endpoints.
28+
*
29+
* @author Madhura Bhave
30+
*/
31+
@RunWith(SpringRunner.class)
32+
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
33+
@DirtiesContext
34+
@ActiveProfiles("cors")
35+
public class CorsSampleActuatorApplicationTests {
36+
37+
private TestRestTemplate testRestTemplate;
38+
39+
@Autowired
40+
ApplicationContext applicationContext;
41+
42+
@Before
43+
public void setUp() throws Exception {
44+
RestTemplate restTemplate = new RestTemplate();
45+
LocalHostUriTemplateHandler handler = new LocalHostUriTemplateHandler(
46+
this.applicationContext.getEnvironment(), "http");
47+
restTemplate.setUriTemplateHandler(handler);
48+
restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
49+
this.testRestTemplate = new TestRestTemplate(restTemplate);
50+
}
51+
52+
@Test
53+
public void sensitiveEndpointShouldReturnUnauthorized() throws Exception {
54+
ResponseEntity<Map> entity = this.testRestTemplate.getForEntity("/env", Map.class);
55+
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
56+
}
57+
58+
@Test
59+
public void preflightRequestForInsensitiveShouldReturnOk() throws Exception {
60+
RequestEntity<?> healthRequest = RequestEntity.options(new URI("/health"))
61+
.header("Origin","http://localhost:8080")
62+
.header("Access-Control-Request-Method", "GET")
63+
.build();
64+
ResponseEntity<Map> exchange = this.testRestTemplate.exchange(healthRequest, Map.class);
65+
assertThat(exchange.getStatusCode()).isEqualTo(HttpStatus.OK);
66+
}
67+
68+
@Test
69+
public void preflightRequestForSensitiveEndpointShouldReturnOk() throws Exception {
70+
RequestEntity<?> entity = RequestEntity.options(new URI("/env"))
71+
.header("Origin","http://localhost:8080")
72+
.header("Access-Control-Request-Method", "GET")
73+
.build();
74+
ResponseEntity<Map> env = this.testRestTemplate.exchange(entity, Map.class);
75+
assertThat(env.getStatusCode()).isEqualTo(HttpStatus.OK);
76+
}
77+
78+
@Test
79+
public void preflightRequestWhenCorsConfigInvalidShouldReturnForbidden() throws Exception {
80+
RequestEntity<?> entity = RequestEntity.options(new URI("/health"))
81+
.header("Origin","http://localhost:9095")
82+
.header("Access-Control-Request-Method", "GET")
83+
.build();
84+
ResponseEntity<byte[]> exchange = this.testRestTemplate.exchange(entity, byte[].class);
85+
assertThat(exchange.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
86+
}
87+
88+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
endpoints.cors.allowed-origins=http://localhost:8080
2+
endpoints.cors.allowed-methods=GET

0 commit comments

Comments
 (0)