|
16 | 16 |
|
17 | 17 | package org.springframework.boot.actuate.autoconfigure.integrationtest; |
18 | 18 |
|
19 | | -import org.junit.Before; |
| 19 | +import java.util.function.Consumer; |
| 20 | + |
20 | 21 | import org.junit.Test; |
21 | 22 |
|
22 | 23 | import org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration; |
|
25 | 26 | import org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive.WebFluxEndpointManagementContextConfiguration; |
26 | 27 | import org.springframework.boot.actuate.autoconfigure.web.reactive.ReactiveManagementContextAutoConfiguration; |
27 | 28 | import org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration; |
| 29 | +import org.springframework.boot.autoconfigure.AutoConfigurations; |
28 | 30 | import org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration; |
29 | 31 | import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; |
30 | 32 | import org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration; |
31 | 33 | import org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration; |
32 | | -import org.springframework.boot.test.util.TestPropertyValues; |
33 | | -import org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext; |
| 34 | +import org.springframework.boot.test.context.runner.ContextConsumer; |
| 35 | +import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner; |
| 36 | +import org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext; |
34 | 37 | import org.springframework.http.HttpHeaders; |
35 | 38 | import org.springframework.test.web.reactive.server.WebTestClient; |
36 | 39 |
|
37 | 40 | /** |
38 | 41 | * Integration tests for the WebFlux actuator endpoints' CORS support |
39 | 42 | * |
40 | 43 | * @author Brian Clozel |
| 44 | + * @author Stephane Nicoll |
41 | 45 | * @see WebFluxEndpointManagementContextConfiguration |
42 | 46 | */ |
43 | 47 | public class WebFluxEndpointCorsIntegrationTests { |
44 | 48 |
|
45 | | - private AnnotationConfigReactiveWebApplicationContext context; |
46 | | - |
47 | | - @Before |
48 | | - public void createContext() { |
49 | | - this.context = new AnnotationConfigReactiveWebApplicationContext(); |
50 | | - this.context.register(JacksonAutoConfiguration.class, |
51 | | - CodecsAutoConfiguration.class, WebFluxAutoConfiguration.class, |
52 | | - HttpHandlerAutoConfiguration.class, EndpointAutoConfiguration.class, |
53 | | - WebEndpointAutoConfiguration.class, |
54 | | - ManagementContextAutoConfiguration.class, |
55 | | - ReactiveManagementContextAutoConfiguration.class, |
56 | | - BeansEndpointAutoConfiguration.class); |
57 | | - TestPropertyValues.of("management.endpoints.web.exposure.include:*") |
58 | | - .applyTo(this.context); |
59 | | - } |
| 49 | + private ReactiveWebApplicationContextRunner contextRunner = new ReactiveWebApplicationContextRunner() |
| 50 | + .withConfiguration(AutoConfigurations.of(JacksonAutoConfiguration.class, |
| 51 | + CodecsAutoConfiguration.class, WebFluxAutoConfiguration.class, |
| 52 | + HttpHandlerAutoConfiguration.class, EndpointAutoConfiguration.class, |
| 53 | + WebEndpointAutoConfiguration.class, |
| 54 | + ManagementContextAutoConfiguration.class, |
| 55 | + ReactiveManagementContextAutoConfiguration.class, |
| 56 | + BeansEndpointAutoConfiguration.class)) |
| 57 | + .withPropertyValues("management.endpoints.web.exposure.include:*"); |
60 | 58 |
|
61 | 59 | @Test |
62 | 60 | public void corsIsDisabledByDefault() { |
63 | | - createWebTestClient().options().uri("/actuator/beans") |
64 | | - .header("Origin", "spring.example.org") |
| 61 | + this.contextRunner.run(withWebTestClient((webTestClient) -> webTestClient |
| 62 | + .options().uri("/actuator/beans").header("Origin", "spring.example.org") |
65 | 63 | .header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET").exchange() |
66 | | - .expectHeader().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN); |
| 64 | + .expectHeader().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN))); |
67 | 65 | } |
68 | 66 |
|
69 | 67 | @Test |
70 | 68 | public void settingAllowedOriginsEnablesCors() { |
71 | | - TestPropertyValues |
72 | | - .of("management.endpoints.web.cors.allowed-origins:spring.example.org") |
73 | | - .applyTo(this.context); |
74 | | - createWebTestClient().options().uri("/actuator/beans") |
75 | | - .header("Origin", "test.example.org") |
76 | | - .header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET").exchange() |
77 | | - .expectStatus().isForbidden(); |
78 | | - performAcceptedCorsRequest("/actuator/beans"); |
| 69 | + this.contextRunner.withPropertyValues( |
| 70 | + "management.endpoints.web.cors.allowed-origins:spring.example.org") |
| 71 | + .run(withWebTestClient((webTestClient) -> { |
| 72 | + webTestClient.options().uri("/actuator/beans") |
| 73 | + .header("Origin", "test.example.org") |
| 74 | + .header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET") |
| 75 | + .exchange().expectStatus().isForbidden(); |
| 76 | + performAcceptedCorsRequest(webTestClient, "/actuator/beans"); |
| 77 | + })); |
79 | 78 | } |
80 | 79 |
|
81 | 80 | @Test |
82 | 81 | public void maxAgeDefaultsTo30Minutes() { |
83 | | - TestPropertyValues |
84 | | - .of("management.endpoints.web.cors.allowed-origins:spring.example.org") |
85 | | - .applyTo(this.context); |
86 | | - performAcceptedCorsRequest("/actuator/beans").expectHeader() |
87 | | - .valueEquals(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "1800"); |
| 82 | + this.contextRunner.withPropertyValues( |
| 83 | + "management.endpoints.web.cors.allowed-origins:spring.example.org") |
| 84 | + .run(withWebTestClient( |
| 85 | + (webTestClient) -> performAcceptedCorsRequest(webTestClient, |
| 86 | + "/actuator/beans").expectHeader().valueEquals( |
| 87 | + HttpHeaders.ACCESS_CONTROL_MAX_AGE, "1800"))); |
88 | 88 | } |
89 | 89 |
|
90 | 90 | @Test |
91 | 91 | public void maxAgeCanBeConfigured() { |
92 | | - TestPropertyValues |
93 | | - .of("management.endpoints.web.cors.allowed-origins:spring.example.org", |
94 | | - "management.endpoints.web.cors.max-age: 2400") |
95 | | - .applyTo(this.context); |
96 | | - performAcceptedCorsRequest("/actuator/beans").expectHeader() |
97 | | - .valueEquals(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "2400"); |
| 92 | + this.contextRunner.withPropertyValues( |
| 93 | + "management.endpoints.web.cors.allowed-origins:spring.example.org", |
| 94 | + "management.endpoints.web.cors.max-age: 2400") |
| 95 | + .run(withWebTestClient( |
| 96 | + (webTestClient) -> performAcceptedCorsRequest(webTestClient, |
| 97 | + "/actuator/beans").expectHeader().valueEquals( |
| 98 | + HttpHeaders.ACCESS_CONTROL_MAX_AGE, "2400"))); |
98 | 99 | } |
99 | 100 |
|
100 | 101 | @Test |
101 | 102 | public void requestsWithDisallowedHeadersAreRejected() { |
102 | | - TestPropertyValues |
103 | | - .of("management.endpoints.web.cors.allowed-origins:spring.example.org") |
104 | | - .applyTo(this.context); |
105 | | - createWebTestClient().options().uri("/actuator/beans") |
106 | | - .header("Origin", "spring.example.org") |
107 | | - .header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET") |
108 | | - .header(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS, "Alpha").exchange() |
109 | | - .expectStatus().isForbidden(); |
| 103 | + this.contextRunner.withPropertyValues( |
| 104 | + "management.endpoints.web.cors.allowed-origins:spring.example.org") |
| 105 | + .run(withWebTestClient((webTestClient) -> webTestClient.options() |
| 106 | + .uri("/actuator/beans").header("Origin", "spring.example.org") |
| 107 | + .header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET") |
| 108 | + .header(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS, "Alpha") |
| 109 | + .exchange().expectStatus().isForbidden())); |
110 | 110 | } |
111 | 111 |
|
112 | 112 | @Test |
113 | 113 | public void allowedHeadersCanBeConfigured() { |
114 | | - TestPropertyValues |
115 | | - .of("management.endpoints.web.cors.allowed-origins:spring.example.org", |
116 | | - "management.endpoints.web.cors.allowed-headers:Alpha,Bravo") |
117 | | - .applyTo(this.context); |
118 | | - createWebTestClient().options().uri("/actuator/beans") |
119 | | - .header("Origin", "spring.example.org") |
120 | | - .header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET") |
121 | | - .header(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS, "Alpha").exchange() |
122 | | - .expectStatus().isOk().expectHeader() |
123 | | - .valueEquals(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "Alpha"); |
| 114 | + this.contextRunner.withPropertyValues( |
| 115 | + "management.endpoints.web.cors.allowed-origins:spring.example.org", |
| 116 | + "management.endpoints.web.cors.allowed-headers:Alpha,Bravo") |
| 117 | + .run(withWebTestClient((webTestClient) -> webTestClient.options() |
| 118 | + .uri("/actuator/beans").header("Origin", "spring.example.org") |
| 119 | + .header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET") |
| 120 | + .header(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS, "Alpha") |
| 121 | + .exchange().expectStatus().isOk().expectHeader() |
| 122 | + .valueEquals(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "Alpha"))); |
124 | 123 | } |
125 | 124 |
|
126 | 125 | @Test |
127 | 126 | public void requestsWithDisallowedMethodsAreRejected() { |
128 | | - TestPropertyValues |
129 | | - .of("management.endpoints.web.cors.allowed-origins:spring.example.org") |
130 | | - .applyTo(this.context); |
131 | | - createWebTestClient().options().uri("/actuator/beans") |
132 | | - .header("Origin", "spring.example.org") |
133 | | - .header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "PATCH").exchange() |
134 | | - .expectStatus().isForbidden(); |
| 127 | + this.contextRunner.withPropertyValues( |
| 128 | + "management.endpoints.web.cors.allowed-origins:spring.example.org") |
| 129 | + .run(withWebTestClient((webTestClient) -> webTestClient.options() |
| 130 | + .uri("/actuator/beans").header("Origin", "spring.example.org") |
| 131 | + .header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "PATCH") |
| 132 | + .exchange().expectStatus().isForbidden())); |
135 | 133 | } |
136 | 134 |
|
137 | 135 | @Test |
138 | 136 | public void allowedMethodsCanBeConfigured() { |
139 | | - TestPropertyValues |
140 | | - .of("management.endpoints.web.cors.allowed-origins:spring.example.org", |
141 | | - "management.endpoints.web.cors.allowed-methods:GET,HEAD") |
142 | | - .applyTo(this.context); |
143 | | - createWebTestClient().options().uri("/actuator/beans") |
144 | | - .header("Origin", "spring.example.org") |
145 | | - .header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "HEAD").exchange() |
146 | | - .expectStatus().isOk().expectHeader() |
147 | | - .valueEquals(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET,HEAD"); |
| 137 | + this.contextRunner.withPropertyValues( |
| 138 | + "management.endpoints.web.cors.allowed-origins:spring.example.org", |
| 139 | + "management.endpoints.web.cors.allowed-methods:GET,HEAD") |
| 140 | + .run(withWebTestClient((webTestClient) -> webTestClient.options() |
| 141 | + .uri("/actuator/beans").header("Origin", "spring.example.org") |
| 142 | + .header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "HEAD") |
| 143 | + .exchange().expectStatus().isOk().expectHeader().valueEquals( |
| 144 | + HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET,HEAD"))); |
148 | 145 | } |
149 | 146 |
|
150 | 147 | @Test |
151 | 148 | public void credentialsCanBeAllowed() { |
152 | | - TestPropertyValues |
153 | | - .of("management.endpoints.web.cors.allowed-origins:spring.example.org", |
154 | | - "management.endpoints.web.cors.allow-credentials:true") |
155 | | - .applyTo(this.context); |
156 | | - performAcceptedCorsRequest("/actuator/beans").expectHeader() |
157 | | - .valueEquals(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"); |
| 149 | + this.contextRunner.withPropertyValues( |
| 150 | + "management.endpoints.web.cors.allowed-origins:spring.example.org", |
| 151 | + "management.endpoints.web.cors.allow-credentials:true") |
| 152 | + .run(withWebTestClient( |
| 153 | + (webTestClient) -> performAcceptedCorsRequest(webTestClient, |
| 154 | + "/actuator/beans").expectHeader().valueEquals( |
| 155 | + HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, |
| 156 | + "true"))); |
158 | 157 | } |
159 | 158 |
|
160 | 159 | @Test |
161 | 160 | public void credentialsCanBeDisabled() { |
162 | | - TestPropertyValues |
163 | | - .of("management.endpoints.web.cors.allowed-origins:spring.example.org", |
164 | | - "management.endpoints.web.cors.allow-credentials:false") |
165 | | - .applyTo(this.context); |
166 | | - performAcceptedCorsRequest("/actuator/beans").expectHeader() |
167 | | - .doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS); |
| 161 | + this.contextRunner.withPropertyValues( |
| 162 | + "management.endpoints.web.cors.allowed-origins:spring.example.org", |
| 163 | + "management.endpoints.web.cors.allow-credentials:false") |
| 164 | + .run(withWebTestClient( |
| 165 | + (webTestClient) -> performAcceptedCorsRequest(webTestClient, |
| 166 | + "/actuator/beans").expectHeader().doesNotExist( |
| 167 | + HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS))); |
168 | 168 | } |
169 | 169 |
|
170 | | - private WebTestClient createWebTestClient() { |
171 | | - this.context.refresh(); |
172 | | - return WebTestClient.bindToApplicationContext(this.context).configureClient() |
173 | | - .baseUrl("https://spring.example.org").build(); |
| 170 | + private ContextConsumer<ReactiveWebApplicationContext> withWebTestClient( |
| 171 | + Consumer<WebTestClient> webTestClient) { |
| 172 | + return (context) -> webTestClient |
| 173 | + .accept(WebTestClient.bindToApplicationContext(context).configureClient() |
| 174 | + .baseUrl("https://spring.example.org").build()); |
174 | 175 | } |
175 | 176 |
|
176 | | - private WebTestClient.ResponseSpec performAcceptedCorsRequest(String url) { |
177 | | - return createWebTestClient().options().uri(url) |
| 177 | + private WebTestClient.ResponseSpec performAcceptedCorsRequest( |
| 178 | + WebTestClient webTestClient, String url) { |
| 179 | + return webTestClient.options().uri(url) |
178 | 180 | .header(HttpHeaders.ORIGIN, "spring.example.org") |
179 | 181 | .header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "GET").exchange() |
180 | 182 | .expectHeader().valueEquals(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, |
|
0 commit comments