Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in / Register
Toggle navigation
S
spring-boot
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
DEMO
spring-boot
Commits
5f3c2bef
Commit
5f3c2bef
authored
Dec 11, 2017
by
Brian Clozel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add CORS support to Actuator WebFlux
Closes gh-11308
parent
deb16e16
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
239 additions
and
30 deletions
+239
-30
WebFluxEndpointManagementContextConfiguration.java
...active/WebFluxEndpointManagementContextConfiguration.java
+35
-2
WebFluxEndpointCorsIntegrationTests.java
.../integrationtest/WebFluxEndpointCorsIntegrationTests.java
+203
-0
WebMvcEndpointCorsIntegrationTests.java
...e/integrationtest/WebMvcEndpointCorsIntegrationTests.java
+1
-28
No files found.
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/endpoint/web/reactive/WebFluxEndpointManagementContextConfiguration.java
View file @
5f3c2bef
...
@@ -17,17 +17,24 @@
...
@@ -17,17 +17,24 @@
package
org
.
springframework
.
boot
.
actuate
.
autoconfigure
.
endpoint
.
web
.
reactive
;
package
org
.
springframework
.
boot
.
actuate
.
autoconfigure
.
endpoint
.
web
.
reactive
;
import
org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties
;
import
org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties
;
import
org.springframework.boot.actuate.autoconfigure.endpoint.web.servlet.CorsEndpointProperties
;
import
org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration
;
import
org.springframework.boot.actuate.autoconfigure.web.ManagementContextConfiguration
;
import
org.springframework.boot.actuate.endpoint.annotation.Endpoint
;
import
org.springframework.boot.actuate.endpoint.annotation.Endpoint
;
import
org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes
;
import
org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes
;
import
org.springframework.boot.actuate.endpoint.web.annotation.WebAnnotationEndpointDiscoverer
;
import
org.springframework.boot.actuate.endpoint.web.annotation.WebAnnotationEndpointDiscoverer
;
import
org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping
;
import
org.springframework.boot.actuate.endpoint.web.reactive.WebFluxEndpointHandlerMapping
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnClass
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type
;
import
org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type
;
import
org.springframework.boot.context.properties.EnableConfigurationProperties
;
import
org.springframework.boot.endpoint.web.EndpointMapping
;
import
org.springframework.boot.endpoint.web.EndpointMapping
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.http.server.reactive.HttpHandler
;
import
org.springframework.util.CollectionUtils
;
import
org.springframework.web.cors.CorsConfiguration
;
import
org.springframework.web.reactive.DispatcherHandler
;
/**
/**
* {@link ManagementContextConfiguration} for Reactive {@link Endpoint} concerns.
* {@link ManagementContextConfiguration} for Reactive {@link Endpoint} concerns.
...
@@ -38,18 +45,44 @@ import org.springframework.context.annotation.Bean;
...
@@ -38,18 +45,44 @@ import org.springframework.context.annotation.Bean;
*/
*/
@ManagementContextConfiguration
@ManagementContextConfiguration
@ConditionalOnWebApplication
(
type
=
Type
.
REACTIVE
)
@ConditionalOnWebApplication
(
type
=
Type
.
REACTIVE
)
@ConditionalOnClass
({
DispatcherHandler
.
class
,
HttpHandler
.
class
})
@ConditionalOnBean
(
WebAnnotationEndpointDiscoverer
.
class
)
@ConditionalOnBean
(
WebAnnotationEndpointDiscoverer
.
class
)
@EnableConfigurationProperties
(
CorsEndpointProperties
.
class
)
public
class
WebFluxEndpointManagementContextConfiguration
{
public
class
WebFluxEndpointManagementContextConfiguration
{
@Bean
@Bean
@ConditionalOnMissingBean
@ConditionalOnMissingBean
public
WebFluxEndpointHandlerMapping
webEndpointReactiveHandlerMapping
(
public
WebFluxEndpointHandlerMapping
webEndpointReactiveHandlerMapping
(
WebAnnotationEndpointDiscoverer
endpointDiscoverer
,
WebAnnotationEndpointDiscoverer
endpointDiscoverer
,
EndpointMediaTypes
endpointMediaTypes
,
EndpointMediaTypes
endpointMediaTypes
,
CorsEndpointProperties
corsProperties
,
WebEndpointProperties
webEndpointProperties
)
{
WebEndpointProperties
webEndpointProperties
)
{
return
new
WebFluxEndpointHandlerMapping
(
return
new
WebFluxEndpointHandlerMapping
(
new
EndpointMapping
(
webEndpointProperties
.
getBasePath
()),
new
EndpointMapping
(
webEndpointProperties
.
getBasePath
()),
endpointDiscoverer
.
discoverEndpoints
(),
endpointMediaTypes
);
endpointDiscoverer
.
discoverEndpoints
(),
endpointMediaTypes
,
getCorsConfiguration
(
corsProperties
));
}
private
CorsConfiguration
getCorsConfiguration
(
CorsEndpointProperties
properties
)
{
if
(
CollectionUtils
.
isEmpty
(
properties
.
getAllowedOrigins
()))
{
return
null
;
}
CorsConfiguration
configuration
=
new
CorsConfiguration
();
configuration
.
setAllowedOrigins
(
properties
.
getAllowedOrigins
());
if
(!
CollectionUtils
.
isEmpty
(
properties
.
getAllowedHeaders
()))
{
configuration
.
setAllowedHeaders
(
properties
.
getAllowedHeaders
());
}
if
(!
CollectionUtils
.
isEmpty
(
properties
.
getAllowedMethods
()))
{
configuration
.
setAllowedMethods
(
properties
.
getAllowedMethods
());
}
if
(!
CollectionUtils
.
isEmpty
(
properties
.
getExposedHeaders
()))
{
configuration
.
setExposedHeaders
(
properties
.
getExposedHeaders
());
}
if
(
properties
.
getMaxAge
()
!=
null
)
{
configuration
.
setMaxAge
(
properties
.
getMaxAge
().
getSeconds
());
}
if
(
properties
.
getAllowCredentials
()
!=
null
)
{
configuration
.
setAllowCredentials
(
properties
.
getAllowCredentials
());
}
return
configuration
;
}
}
}
}
spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/WebFluxEndpointCorsIntegrationTests.java
0 → 100644
View file @
5f3c2bef
/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
actuate
.
autoconfigure
.
integrationtest
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfiguration
;
import
org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration
;
import
org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAutoConfiguration
;
import
org.springframework.boot.actuate.autoconfigure.endpoint.web.reactive.WebFluxEndpointManagementContextConfiguration
;
import
org.springframework.boot.actuate.autoconfigure.web.reactive.ReactiveManagementContextAutoConfiguration
;
import
org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration
;
import
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport
;
import
org.springframework.boot.autoconfigure.http.codec.CodecsAutoConfiguration
;
import
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
;
import
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportMessage
;
import
org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration
;
import
org.springframework.boot.autoconfigure.web.reactive.WebFluxAutoConfiguration
;
import
org.springframework.boot.test.util.TestPropertyValues
;
import
org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebApplicationContext
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.test.web.reactive.server.WebTestClient
;
/**
* Integration tests for the WebFlux actuator endpoints' CORS support
*
* @author Brian Clozel
* @see WebFluxEndpointManagementContextConfiguration
*/
public
class
WebFluxEndpointCorsIntegrationTests
{
private
AnnotationConfigReactiveWebApplicationContext
context
;
@Before
public
void
createContext
()
{
this
.
context
=
new
AnnotationConfigReactiveWebApplicationContext
();
this
.
context
.
register
(
JacksonAutoConfiguration
.
class
,
CodecsAutoConfiguration
.
class
,
WebFluxAutoConfiguration
.
class
,
HttpHandlerAutoConfiguration
.
class
,
EndpointAutoConfiguration
.
class
,
WebEndpointAutoConfiguration
.
class
,
ManagementContextAutoConfiguration
.
class
,
ReactiveManagementContextAutoConfiguration
.
class
,
BeansEndpointAutoConfiguration
.
class
);
TestPropertyValues
.
of
(
"management.endpoints.web.expose:*"
).
applyTo
(
this
.
context
);
}
@Test
public
void
corsIsDisabledByDefault
()
throws
Exception
{
WebTestClient
client
=
createWebTestClient
();
System
.
out
.
println
(
new
ConditionEvaluationReportMessage
(
this
.
context
.
getBean
(
ConditionEvaluationReport
.
class
)));
client
.
options
().
uri
(
"/actuator/beans"
)
.
header
(
"Origin"
,
"spring.example.org"
)
.
header
(
HttpHeaders
.
ACCESS_CONTROL_REQUEST_METHOD
,
"GET"
)
.
exchange
()
.
expectStatus
().
isForbidden
();
//TODO: .expectHeader().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN);
}
@Test
public
void
settingAllowedOriginsEnablesCors
()
throws
Exception
{
TestPropertyValues
.
of
(
"management.endpoints.web.cors.allowed-origins:spring.example.org"
)
.
applyTo
(
this
.
context
);
createWebTestClient
()
.
options
().
uri
(
"/actuator/beans"
)
.
header
(
"Origin"
,
"test.example.org"
)
.
header
(
HttpHeaders
.
ACCESS_CONTROL_REQUEST_METHOD
,
"GET"
)
.
exchange
()
.
expectStatus
().
isForbidden
();
performAcceptedCorsRequest
(
"/actuator/beans"
);
}
@Test
public
void
maxAgeDefaultsTo30Minutes
()
throws
Exception
{
TestPropertyValues
.
of
(
"management.endpoints.web.cors.allowed-origins:spring.example.org"
)
.
applyTo
(
this
.
context
);
performAcceptedCorsRequest
(
"/actuator/beans"
)
.
expectHeader
().
valueEquals
(
HttpHeaders
.
ACCESS_CONTROL_MAX_AGE
,
"1800"
);
}
@Test
public
void
maxAgeCanBeConfigured
()
throws
Exception
{
TestPropertyValues
.
of
(
"management.endpoints.web.cors.allowed-origins:spring.example.org"
,
"management.endpoints.web.cors.max-age: 2400"
)
.
applyTo
(
this
.
context
);
performAcceptedCorsRequest
(
"/actuator/beans"
)
.
expectHeader
().
valueEquals
(
HttpHeaders
.
ACCESS_CONTROL_MAX_AGE
,
"2400"
);
}
@Test
public
void
requestsWithDisallowedHeadersAreRejected
()
throws
Exception
{
TestPropertyValues
.
of
(
"management.endpoints.web.cors.allowed-origins:spring.example.org"
)
.
applyTo
(
this
.
context
);
createWebTestClient
()
.
options
().
uri
(
"/actuator/beans"
)
.
header
(
"Origin"
,
"spring.example.org"
)
.
header
(
HttpHeaders
.
ACCESS_CONTROL_REQUEST_METHOD
,
"GET"
)
.
header
(
HttpHeaders
.
ACCESS_CONTROL_REQUEST_HEADERS
,
"Alpha"
)
.
exchange
()
.
expectStatus
().
isForbidden
();
}
@Test
public
void
allowedHeadersCanBeConfigured
()
throws
Exception
{
TestPropertyValues
.
of
(
"management.endpoints.web.cors.allowed-origins:spring.example.org"
,
"management.endpoints.web.cors.allowed-headers:Alpha,Bravo"
)
.
applyTo
(
this
.
context
);
createWebTestClient
()
.
options
().
uri
(
"/actuator/beans"
)
.
header
(
"Origin"
,
"spring.example.org"
)
.
header
(
HttpHeaders
.
ACCESS_CONTROL_REQUEST_METHOD
,
"GET"
)
.
header
(
HttpHeaders
.
ACCESS_CONTROL_REQUEST_HEADERS
,
"Alpha"
)
.
exchange
()
.
expectStatus
().
isOk
()
.
expectHeader
().
valueEquals
(
HttpHeaders
.
ACCESS_CONTROL_ALLOW_HEADERS
,
"Alpha"
);
}
@Test
public
void
requestsWithDisallowedMethodsAreRejected
()
throws
Exception
{
TestPropertyValues
.
of
(
"management.endpoints.web.cors.allowed-origins:spring.example.org"
)
.
applyTo
(
this
.
context
);
createWebTestClient
()
.
options
().
uri
(
"/actuator/beans"
)
.
header
(
"Origin"
,
"spring.example.org"
)
.
header
(
HttpHeaders
.
ACCESS_CONTROL_REQUEST_METHOD
,
"PATCH"
)
.
exchange
()
.
expectStatus
().
isForbidden
();
}
@Test
public
void
allowedMethodsCanBeConfigured
()
throws
Exception
{
TestPropertyValues
.
of
(
"management.endpoints.web.cors.allowed-origins:spring.example.org"
,
"management.endpoints.web.cors.allowed-methods:GET,HEAD"
)
.
applyTo
(
this
.
context
);
createWebTestClient
()
.
options
().
uri
(
"/actuator/beans"
)
.
header
(
"Origin"
,
"spring.example.org"
)
.
header
(
HttpHeaders
.
ACCESS_CONTROL_REQUEST_METHOD
,
"HEAD"
)
.
exchange
()
.
expectStatus
().
isOk
()
.
expectHeader
().
valueEquals
(
HttpHeaders
.
ACCESS_CONTROL_ALLOW_METHODS
,
"GET,HEAD"
);
}
@Test
public
void
credentialsCanBeAllowed
()
throws
Exception
{
TestPropertyValues
.
of
(
"management.endpoints.web.cors.allowed-origins:spring.example.org"
,
"management.endpoints.web.cors.allow-credentials:true"
)
.
applyTo
(
this
.
context
);
performAcceptedCorsRequest
(
"/actuator/beans"
)
.
expectHeader
().
valueEquals
(
HttpHeaders
.
ACCESS_CONTROL_ALLOW_CREDENTIALS
,
"true"
);
}
@Test
public
void
credentialsCanBeDisabled
()
throws
Exception
{
TestPropertyValues
.
of
(
"management.endpoints.web.cors.allowed-origins:spring.example.org"
,
"management.endpoints.web.cors.allow-credentials:false"
)
.
applyTo
(
this
.
context
);
performAcceptedCorsRequest
(
"/actuator/beans"
);
//TODO .expectHeader().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS);
}
private
WebTestClient
createWebTestClient
()
{
this
.
context
.
refresh
();
return
WebTestClient
.
bindToApplicationContext
(
this
.
context
)
.
configureClient
().
baseUrl
(
"https://spring.example.org"
).
build
();
}
private
WebTestClient
.
ResponseSpec
performAcceptedCorsRequest
(
String
url
)
throws
Exception
{
return
createWebTestClient
()
.
options
().
uri
(
url
)
.
header
(
HttpHeaders
.
ORIGIN
,
"spring.example.org"
)
.
header
(
HttpHeaders
.
ACCESS_CONTROL_REQUEST_METHOD
,
"GET"
)
.
exchange
()
.
expectHeader
().
valueEquals
(
HttpHeaders
.
ACCESS_CONTROL_ALLOW_ORIGIN
,
"spring.example.org"
)
.
expectStatus
().
isOk
();
}
}
spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/integrationtest/WebMvcEndpointCorsIntegrationTests.java
View file @
5f3c2bef
...
@@ -25,7 +25,6 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAu
...
@@ -25,7 +25,6 @@ import org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointAu
import
org.springframework.boot.actuate.autoconfigure.endpoint.web.servlet.WebMvcEndpointManagementContextConfiguration
;
import
org.springframework.boot.actuate.autoconfigure.endpoint.web.servlet.WebMvcEndpointManagementContextConfiguration
;
import
org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration
;
import
org.springframework.boot.actuate.autoconfigure.web.server.ManagementContextAutoConfiguration
;
import
org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration
;
import
org.springframework.boot.actuate.autoconfigure.web.servlet.ServletManagementContextAutoConfiguration
;
import
org.springframework.boot.actuate.beans.BeansEndpoint
;
import
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport
;
import
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport
;
import
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration
;
import
org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration
;
import
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
;
import
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
;
...
@@ -33,13 +32,8 @@ import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportM
...
@@ -33,13 +32,8 @@ import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportM
import
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
;
import
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
;
import
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
;
import
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
;
import
org.springframework.boot.test.util.TestPropertyValues
;
import
org.springframework.boot.test.util.TestPropertyValues
;
import
org.springframework.context.ConfigurableApplicationContext
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.http.HttpHeaders
;
import
org.springframework.mock.web.MockServletContext
;
import
org.springframework.mock.web.MockServletContext
;
import
org.springframework.security.config.annotation.web.builders.HttpSecurity
;
import
org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
;
import
org.springframework.test.web.servlet.MockMvc
;
import
org.springframework.test.web.servlet.MockMvc
;
import
org.springframework.test.web.servlet.ResultActions
;
import
org.springframework.test.web.servlet.ResultActions
;
import
org.springframework.test.web.servlet.setup.MockMvcBuilders
;
import
org.springframework.test.web.servlet.setup.MockMvcBuilders
;
...
@@ -50,7 +44,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
...
@@ -50,7 +44,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
import
static
org
.
springframework
.
test
.
web
.
servlet
.
result
.
MockMvcResultMatchers
.
status
;
import
static
org
.
springframework
.
test
.
web
.
servlet
.
result
.
MockMvcResultMatchers
.
status
;
/**
/**
* Integration tests for the actuator endpoints' CORS support
* Integration tests for the
MVC
actuator endpoints' CORS support
*
*
* @author Andy Wilkinson
* @author Andy Wilkinson
* @see WebMvcEndpointManagementContextConfiguration
* @see WebMvcEndpointManagementContextConfiguration
...
@@ -204,25 +198,4 @@ public class WebMvcEndpointCorsIntegrationTests {
...
@@ -204,25 +198,4 @@ public class WebMvcEndpointCorsIntegrationTests {
.
andExpect
(
status
().
isOk
());
.
andExpect
(
status
().
isOk
());
}
}
@Configuration
static
class
EndpointConfiguration
{
@Bean
public
BeansEndpoint
beansEndpoint
(
ConfigurableApplicationContext
applicationContext
)
{
return
new
BeansEndpoint
(
applicationContext
);
}
}
@Configuration
static
class
SecurityConfiguration
extends
WebSecurityConfigurerAdapter
{
@Override
protected
void
configure
(
HttpSecurity
http
)
throws
Exception
{
http
.
cors
();
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment