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
3f00ba3c
Commit
3f00ba3c
authored
Nov 03, 2017
by
Phillip Webb
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Polish
parent
200eb8f5
Changes
21
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
21 changed files
with
454 additions
and
399 deletions
+454
-399
AccessLevel.java
.../boot/actuate/autoconfigure/cloudfoundry/AccessLevel.java
+1
-0
CloudFoundryAuthorizationException.java
...gure/cloudfoundry/CloudFoundryAuthorizationException.java
+3
-1
SecurityResponse.java
.../actuate/autoconfigure/cloudfoundry/SecurityResponse.java
+1
-0
Token.java
...mework/boot/actuate/autoconfigure/cloudfoundry/Token.java
+6
-10
CloudFoundryWebFluxEndpointHandlerMapping.java
...y/reactive/CloudFoundryWebFluxEndpointHandlerMapping.java
+51
-43
ReactiveCloudFoundryActuatorAutoConfiguration.java
...active/ReactiveCloudFoundryActuatorAutoConfiguration.java
+31
-21
ReactiveCloudFoundrySecurityInterceptor.java
...dry/reactive/ReactiveCloudFoundrySecurityInterceptor.java
+16
-14
ReactiveCloudFoundrySecurityService.java
...foundry/reactive/ReactiveCloudFoundrySecurityService.java
+40
-35
ReactiveTokenValidator.java
...nfigure/cloudfoundry/reactive/ReactiveTokenValidator.java
+18
-29
CloudFoundryActuatorAutoConfiguration.java
...oundry/servlet/CloudFoundryActuatorAutoConfiguration.java
+4
-6
CloudFoundrySecurityInterceptor.java
...cloudfoundry/servlet/CloudFoundrySecurityInterceptor.java
+4
-8
CloudFoundryWebEndpointServletHandlerMapping.java
...servlet/CloudFoundryWebEndpointServletHandlerMapping.java
+5
-5
TokenValidator.java
...te/autoconfigure/cloudfoundry/servlet/TokenValidator.java
+2
-2
CloudFoundryWebFluxEndpointIntegrationTests.java
...reactive/CloudFoundryWebFluxEndpointIntegrationTests.java
+8
-6
ReactiveCloudFoundryActuatorAutoConfigurationTests.java
...e/ReactiveCloudFoundryActuatorAutoConfigurationTests.java
+27
-23
ReactiveCloudFoundrySecurityInterceptorTests.java
...eactive/ReactiveCloudFoundrySecurityInterceptorTests.java
+53
-57
ReactiveCloudFoundrySecurityServiceTests.java
...ry/reactive/ReactiveCloudFoundrySecurityServiceTests.java
+83
-58
ReactiveTokenValidatorTests.java
...re/cloudfoundry/reactive/ReactiveTokenValidatorTests.java
+73
-48
CloudFoundrySecurityInterceptorTests.java
...foundry/servlet/CloudFoundrySecurityInterceptorTests.java
+8
-16
AbstractWebFluxEndpointHandlerMapping.java
...t/web/reactive/AbstractWebFluxEndpointHandlerMapping.java
+13
-14
WebFluxEndpointHandlerMapping.java
.../endpoint/web/reactive/WebFluxEndpointHandlerMapping.java
+7
-3
No files found.
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/AccessLevel.java
View file @
3f00ba3c
...
@@ -24,6 +24,7 @@ import java.util.List;
...
@@ -24,6 +24,7 @@ import java.util.List;
* endpoints.
* endpoints.
*
*
* @author Madhura Bhave
* @author Madhura Bhave
* @since 2.0.0
*/
*/
public
enum
AccessLevel
{
public
enum
AccessLevel
{
...
...
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/CloudFoundryAuthorizationException.java
View file @
3f00ba3c
...
@@ -22,6 +22,7 @@ import org.springframework.http.HttpStatus;
...
@@ -22,6 +22,7 @@ import org.springframework.http.HttpStatus;
* Authorization exceptions thrown to limit access to the endpoints.
* Authorization exceptions thrown to limit access to the endpoints.
*
*
* @author Madhura Bhave
* @author Madhura Bhave
* @since 2.0.0
*/
*/
public
class
CloudFoundryAuthorizationException
extends
RuntimeException
{
public
class
CloudFoundryAuthorizationException
extends
RuntimeException
{
...
@@ -31,7 +32,8 @@ public class CloudFoundryAuthorizationException extends RuntimeException {
...
@@ -31,7 +32,8 @@ public class CloudFoundryAuthorizationException extends RuntimeException {
this
(
reason
,
message
,
null
);
this
(
reason
,
message
,
null
);
}
}
public
CloudFoundryAuthorizationException
(
Reason
reason
,
String
message
,
Throwable
cause
)
{
public
CloudFoundryAuthorizationException
(
Reason
reason
,
String
message
,
Throwable
cause
)
{
super
(
message
);
super
(
message
);
this
.
reason
=
reason
;
this
.
reason
=
reason
;
}
}
...
...
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/SecurityResponse.java
View file @
3f00ba3c
...
@@ -22,6 +22,7 @@ import org.springframework.http.HttpStatus;
...
@@ -22,6 +22,7 @@ import org.springframework.http.HttpStatus;
* Response from the Cloud Foundry security interceptors.
* Response from the Cloud Foundry security interceptors.
*
*
* @author Madhura Bhave
* @author Madhura Bhave
* @since 2.0.0
*/
*/
public
class
SecurityResponse
{
public
class
SecurityResponse
{
...
...
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/Token.java
View file @
3f00ba3c
...
@@ -29,6 +29,7 @@ import org.springframework.util.StringUtils;
...
@@ -29,6 +29,7 @@ import org.springframework.util.StringUtils;
* The JSON web token provided with each request that originates from Cloud Foundry.
* The JSON web token provided with each request that originates from Cloud Foundry.
*
*
* @author Madhura Bhave
* @author Madhura Bhave
* @since 2.0.0
*/
*/
public
class
Token
{
public
class
Token
{
...
@@ -47,16 +48,14 @@ public class Token {
...
@@ -47,16 +48,14 @@ public class Token {
int
firstPeriod
=
encoded
.
indexOf
(
'.'
);
int
firstPeriod
=
encoded
.
indexOf
(
'.'
);
int
lastPeriod
=
encoded
.
lastIndexOf
(
'.'
);
int
lastPeriod
=
encoded
.
lastIndexOf
(
'.'
);
if
(
firstPeriod
<=
0
||
lastPeriod
<=
firstPeriod
)
{
if
(
firstPeriod
<=
0
||
lastPeriod
<=
firstPeriod
)
{
throw
new
CloudFoundryAuthorizationException
(
throw
new
CloudFoundryAuthorizationException
(
Reason
.
INVALID_TOKEN
,
Reason
.
INVALID_TOKEN
,
"JWT must have header, body and signature"
);
"JWT must have header, body and signature"
);
}
}
this
.
header
=
parseJson
(
encoded
.
substring
(
0
,
firstPeriod
));
this
.
header
=
parseJson
(
encoded
.
substring
(
0
,
firstPeriod
));
this
.
claims
=
parseJson
(
encoded
.
substring
(
firstPeriod
+
1
,
lastPeriod
));
this
.
claims
=
parseJson
(
encoded
.
substring
(
firstPeriod
+
1
,
lastPeriod
));
this
.
signature
=
encoded
.
substring
(
lastPeriod
+
1
);
this
.
signature
=
encoded
.
substring
(
lastPeriod
+
1
);
if
(!
StringUtils
.
hasLength
(
this
.
signature
))
{
if
(!
StringUtils
.
hasLength
(
this
.
signature
))
{
throw
new
CloudFoundryAuthorizationException
(
throw
new
CloudFoundryAuthorizationException
(
Reason
.
INVALID_TOKEN
,
Reason
.
INVALID_TOKEN
,
"Token must have non-empty crypto segment"
);
"Token must have non-empty crypto segment"
);
}
}
}
}
...
@@ -67,8 +66,7 @@ public class Token {
...
@@ -67,8 +66,7 @@ public class Token {
return
JsonParserFactory
.
getJsonParser
().
parseMap
(
new
String
(
bytes
,
UTF_8
));
return
JsonParserFactory
.
getJsonParser
().
parseMap
(
new
String
(
bytes
,
UTF_8
));
}
}
catch
(
RuntimeException
ex
)
{
catch
(
RuntimeException
ex
)
{
throw
new
CloudFoundryAuthorizationException
(
throw
new
CloudFoundryAuthorizationException
(
Reason
.
INVALID_TOKEN
,
Reason
.
INVALID_TOKEN
,
"Token could not be parsed"
,
ex
);
"Token could not be parsed"
,
ex
);
}
}
}
}
...
@@ -106,13 +104,11 @@ public class Token {
...
@@ -106,13 +104,11 @@ public class Token {
private
<
T
>
T
getRequired
(
Map
<
String
,
Object
>
map
,
String
key
,
Class
<
T
>
type
)
{
private
<
T
>
T
getRequired
(
Map
<
String
,
Object
>
map
,
String
key
,
Class
<
T
>
type
)
{
Object
value
=
map
.
get
(
key
);
Object
value
=
map
.
get
(
key
);
if
(
value
==
null
)
{
if
(
value
==
null
)
{
throw
new
CloudFoundryAuthorizationException
(
throw
new
CloudFoundryAuthorizationException
(
Reason
.
INVALID_TOKEN
,
Reason
.
INVALID_TOKEN
,
"Unable to get value from key "
+
key
);
"Unable to get value from key "
+
key
);
}
}
if
(!
type
.
isInstance
(
value
))
{
if
(!
type
.
isInstance
(
value
))
{
throw
new
CloudFoundryAuthorizationException
(
throw
new
CloudFoundryAuthorizationException
(
Reason
.
INVALID_TOKEN
,
Reason
.
INVALID_TOKEN
,
"Unexpected value type from key "
+
key
+
" value "
+
value
);
"Unexpected value type from key "
+
key
+
" value "
+
value
);
}
}
return
(
T
)
value
;
return
(
T
)
value
;
...
...
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundryWebFluxEndpointHandlerMapping.java
View file @
3f00ba3c
...
@@ -28,6 +28,7 @@ import org.reactivestreams.Publisher;
...
@@ -28,6 +28,7 @@ import org.reactivestreams.Publisher;
import
reactor.core.publisher.Mono
;
import
reactor.core.publisher.Mono
;
import
org.springframework.boot.actuate.autoconfigure.cloudfoundry.AccessLevel
;
import
org.springframework.boot.actuate.autoconfigure.cloudfoundry.AccessLevel
;
import
org.springframework.boot.actuate.autoconfigure.cloudfoundry.SecurityResponse
;
import
org.springframework.boot.actuate.endpoint.EndpointInfo
;
import
org.springframework.boot.actuate.endpoint.EndpointInfo
;
import
org.springframework.boot.actuate.endpoint.OperationInvoker
;
import
org.springframework.boot.actuate.endpoint.OperationInvoker
;
import
org.springframework.boot.actuate.endpoint.OperationType
;
import
org.springframework.boot.actuate.endpoint.OperationType
;
...
@@ -58,7 +59,8 @@ import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMappi
...
@@ -58,7 +59,8 @@ import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMappi
*
*
* @author Madhura Bhave
* @author Madhura Bhave
*/
*/
public
class
CloudFoundryWebFluxEndpointHandlerMapping
extends
AbstractWebFluxEndpointHandlerMapping
{
class
CloudFoundryWebFluxEndpointHandlerMapping
extends
AbstractWebFluxEndpointHandlerMapping
{
private
final
Method
handleRead
=
ReflectionUtils
private
final
Method
handleRead
=
ReflectionUtils
.
findMethod
(
ReadOperationHandler
.
class
,
"handle"
,
ServerWebExchange
.
class
);
.
findMethod
(
ReadOperationHandler
.
class
,
"handle"
,
ServerWebExchange
.
class
);
...
@@ -85,38 +87,38 @@ public class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEn
...
@@ -85,38 +87,38 @@ public class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEn
if
(
operation
.
isBlocking
())
{
if
(
operation
.
isBlocking
())
{
operationInvoker
=
new
ElasticSchedulerOperationInvoker
(
operationInvoker
);
operationInvoker
=
new
ElasticSchedulerOperationInvoker
(
operationInvoker
);
}
}
registerMapping
(
createRequestMappingInfo
(
operation
),
Object
handler
=
(
operationType
==
OperationType
.
WRITE
operationType
==
OperationType
.
WRITE
?
new
WriteOperationHandler
(
operationInvoker
,
operation
.
getId
())
?
new
WriteOperationHandler
(
operationInvoker
,
operation
.
getId
())
:
new
ReadOperationHandler
(
operationInvoker
,
operation
.
getId
()),
:
new
ReadOperationHandler
(
operationInvoker
,
operation
.
getId
()));
operationType
==
OperationType
.
WRITE
?
this
.
handleWrite
Method
method
=
(
operationType
==
OperationType
.
WRITE
?
this
.
handleWrite
:
this
.
handleRead
);
:
this
.
handleRead
);
registerMapping
(
createRequestMappingInfo
(
operation
),
handler
,
method
);
}
}
@ResponseBody
@ResponseBody
private
Publisher
<
ResponseEntity
<
Object
>>
links
(
ServerWebExchange
exchange
)
{
private
Publisher
<
ResponseEntity
<
Object
>>
links
(
ServerWebExchange
exchange
)
{
ServerHttpRequest
request
=
exchange
.
getRequest
();
ServerHttpRequest
request
=
exchange
.
getRequest
();
return
this
.
securityInterceptor
return
this
.
securityInterceptor
.
preHandle
(
exchange
,
""
).
map
(
securityResponse
->
{
.
preHandle
(
exchange
,
""
)
.
map
(
securityResponse
->
{
if
(!
securityResponse
.
getStatus
().
equals
(
HttpStatus
.
OK
))
{
if
(!
securityResponse
.
getStatus
().
equals
(
HttpStatus
.
OK
))
{
return
new
ResponseEntity
<>(
securityResponse
.
getStatus
());
return
new
ResponseEntity
<>(
securityResponse
.
getStatus
());
}
}
AccessLevel
accessLevel
=
exchange
.
getAttribute
(
AccessLevel
.
REQUEST_ATTRIBUTE
);
AccessLevel
accessLevel
=
exchange
Map
<
String
,
Link
>
links
=
this
.
endpointLinksResolver
.
resolveLinks
(
getEndpoints
(),
.
getAttribute
(
AccessLevel
.
REQUEST_ATTRIBUTE
);
request
.
getURI
().
toString
());
Map
<
String
,
Link
>
links
=
this
.
endpointLinksResolver
.
resolveLinks
(
getEndpoints
(),
request
.
getURI
().
toString
());
return
new
ResponseEntity
<>(
Collections
.
singletonMap
(
"_links"
,
return
new
ResponseEntity
<>(
Collections
.
singletonMap
(
"_links"
,
getAccessibleLinks
(
accessLevel
,
links
)),
HttpStatus
.
OK
);
getAccessibleLinks
(
accessLevel
,
links
)),
HttpStatus
.
OK
);
});
});
}
}
private
Map
<
String
,
Link
>
getAccessibleLinks
(
AccessLevel
accessLevel
,
Map
<
String
,
Link
>
links
)
{
private
Map
<
String
,
Link
>
getAccessibleLinks
(
AccessLevel
accessLevel
,
Map
<
String
,
Link
>
links
)
{
if
(
accessLevel
==
null
)
{
if
(
accessLevel
==
null
)
{
return
new
LinkedHashMap
<>();
return
new
LinkedHashMap
<>();
}
}
return
links
.
entrySet
().
stream
()
return
links
.
entrySet
().
stream
()
.
filter
((
e
)
->
e
.
getKey
().
equals
(
"self"
)
.
filter
((
e
ntry
)
->
entry
.
getKey
().
equals
(
"self"
)
||
accessLevel
.
isAccessAllowed
(
e
.
getKey
()))
||
accessLevel
.
isAccessAllowed
(
e
ntry
.
getKey
()))
.
collect
(
Collectors
.
toMap
(
Map
.
Entry
::
getKey
,
Map
.
Entry
::
getValue
));
.
collect
(
Collectors
.
toMap
(
Map
.
Entry
::
getKey
,
Map
.
Entry
::
getValue
));
}
}
...
@@ -129,7 +131,7 @@ public class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEn
...
@@ -129,7 +131,7 @@ public class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEn
* @param corsConfiguration the CORS configuration for the endpoints
* @param corsConfiguration the CORS configuration for the endpoints
* @param securityInterceptor the Security Interceptor
* @param securityInterceptor the Security Interceptor
*/
*/
public
CloudFoundryWebFluxEndpointHandlerMapping
(
EndpointMapping
endpointMapping
,
CloudFoundryWebFluxEndpointHandlerMapping
(
EndpointMapping
endpointMapping
,
Collection
<
EndpointInfo
<
WebEndpointOperation
>>
webEndpoints
,
Collection
<
EndpointInfo
<
WebEndpointOperation
>>
webEndpoints
,
EndpointMediaTypes
endpointMediaTypes
,
CorsConfiguration
corsConfiguration
,
EndpointMediaTypes
endpointMediaTypes
,
CorsConfiguration
corsConfiguration
,
ReactiveCloudFoundrySecurityInterceptor
securityInterceptor
)
{
ReactiveCloudFoundrySecurityInterceptor
securityInterceptor
)
{
...
@@ -148,18 +150,23 @@ public class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEn
...
@@ -148,18 +150,23 @@ public class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEn
private
final
ReactiveCloudFoundrySecurityInterceptor
securityInterceptor
;
private
final
ReactiveCloudFoundrySecurityInterceptor
securityInterceptor
;
AbstractOperationHandler
(
OperationInvoker
operationInvoker
,
String
endpointId
,
ReactiveCloudFoundrySecurityInterceptor
securityInterceptor
)
{
AbstractOperationHandler
(
OperationInvoker
operationInvoker
,
String
endpointId
,
ReactiveCloudFoundrySecurityInterceptor
securityInterceptor
)
{
this
.
operationInvoker
=
operationInvoker
;
this
.
operationInvoker
=
operationInvoker
;
this
.
endpointId
=
endpointId
;
this
.
endpointId
=
endpointId
;
this
.
securityInterceptor
=
securityInterceptor
;
this
.
securityInterceptor
=
securityInterceptor
;
}
}
@SuppressWarnings
({
"unchecked"
})
Publisher
<
ResponseEntity
<
Object
>>
doHandle
(
ServerWebExchange
exchange
,
Publisher
<
ResponseEntity
<
Object
>>
doHandle
(
ServerWebExchange
exchange
,
Map
<
String
,
String
>
body
)
{
Map
<
String
,
String
>
body
)
{
return
this
.
securityInterceptor
return
this
.
securityInterceptor
.
preHandle
(
exchange
,
this
.
endpointId
)
.
preHandle
(
exchange
,
this
.
endpointId
)
.
flatMap
((
securityResponse
)
->
flatMapResponse
(
exchange
,
body
,
.
flatMap
(
securityResponse
->
{
securityResponse
));
}
private
Mono
<?
extends
ResponseEntity
<
Object
>>
flatMapResponse
(
ServerWebExchange
exchange
,
Map
<
String
,
String
>
body
,
SecurityResponse
securityResponse
)
{
if
(!
securityResponse
.
getStatus
().
equals
(
HttpStatus
.
OK
))
{
if
(!
securityResponse
.
getStatus
().
equals
(
HttpStatus
.
OK
))
{
return
Mono
.
just
(
new
ResponseEntity
<>(
securityResponse
.
getStatus
()));
return
Mono
.
just
(
new
ResponseEntity
<>(
securityResponse
.
getStatus
()));
}
}
...
@@ -169,10 +176,9 @@ public class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEn
...
@@ -169,10 +176,9 @@ public class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEn
arguments
.
putAll
(
body
);
arguments
.
putAll
(
body
);
}
}
exchange
.
getRequest
().
getQueryParams
().
forEach
((
name
,
values
)
->
arguments
exchange
.
getRequest
().
getQueryParams
().
forEach
((
name
,
values
)
->
arguments
.
put
(
name
,
values
.
size
()
==
1
?
values
.
get
(
0
)
:
values
));
.
put
(
name
,
(
values
.
size
()
==
1
?
values
.
get
(
0
)
:
values
)
));
return
handleResult
((
Publisher
<?>)
this
.
operationInvoker
.
invoke
(
arguments
),
return
handleResult
((
Publisher
<?>)
this
.
operationInvoker
.
invoke
(
arguments
),
exchange
.
getRequest
().
getMethod
());
exchange
.
getRequest
().
getMethod
());
});
}
}
private
Mono
<
ResponseEntity
<
Object
>>
handleResult
(
Publisher
<?>
result
,
private
Mono
<
ResponseEntity
<
Object
>>
handleResult
(
Publisher
<?>
result
,
...
@@ -203,7 +209,8 @@ public class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEn
...
@@ -203,7 +209,8 @@ public class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEn
final
class
WriteOperationHandler
extends
AbstractOperationHandler
{
final
class
WriteOperationHandler
extends
AbstractOperationHandler
{
WriteOperationHandler
(
OperationInvoker
operationInvoker
,
String
endpointId
)
{
WriteOperationHandler
(
OperationInvoker
operationInvoker
,
String
endpointId
)
{
super
(
operationInvoker
,
endpointId
,
CloudFoundryWebFluxEndpointHandlerMapping
.
this
.
securityInterceptor
);
super
(
operationInvoker
,
endpointId
,
CloudFoundryWebFluxEndpointHandlerMapping
.
this
.
securityInterceptor
);
}
}
@ResponseBody
@ResponseBody
...
@@ -220,7 +227,8 @@ public class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEn
...
@@ -220,7 +227,8 @@ public class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEn
final
class
ReadOperationHandler
extends
AbstractOperationHandler
{
final
class
ReadOperationHandler
extends
AbstractOperationHandler
{
ReadOperationHandler
(
OperationInvoker
operationInvoker
,
String
endpointId
)
{
ReadOperationHandler
(
OperationInvoker
operationInvoker
,
String
endpointId
)
{
super
(
operationInvoker
,
endpointId
,
CloudFoundryWebFluxEndpointHandlerMapping
.
this
.
securityInterceptor
);
super
(
operationInvoker
,
endpointId
,
CloudFoundryWebFluxEndpointHandlerMapping
.
this
.
securityInterceptor
);
}
}
@ResponseBody
@ResponseBody
...
...
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfiguration.java
View file @
3f00ba3c
...
@@ -69,13 +69,16 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration {
...
@@ -69,13 +69,16 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration {
public
CloudFoundryWebFluxEndpointHandlerMapping
cloudFoundryWebFluxEndpointHandlerMapping
(
public
CloudFoundryWebFluxEndpointHandlerMapping
cloudFoundryWebFluxEndpointHandlerMapping
(
ParameterMapper
parameterMapper
,
EndpointMediaTypes
endpointMediaTypes
,
ParameterMapper
parameterMapper
,
EndpointMediaTypes
endpointMediaTypes
,
WebClient
.
Builder
webClientBuilder
,
Environment
environment
,
WebClient
.
Builder
webClientBuilder
,
Environment
environment
,
DefaultCachingConfigurationFactory
cachingConfigurationFactory
,
WebEndpointProperties
webEndpointProperties
)
{
DefaultCachingConfigurationFactory
cachingConfigurationFactory
,
WebEndpointProperties
webEndpointProperties
)
{
WebAnnotationEndpointDiscoverer
endpointDiscoverer
=
new
WebAnnotationEndpointDiscoverer
(
WebAnnotationEndpointDiscoverer
endpointDiscoverer
=
new
WebAnnotationEndpointDiscoverer
(
this
.
applicationContext
,
parameterMapper
,
cachingConfigurationFactory
,
this
.
applicationContext
,
parameterMapper
,
cachingConfigurationFactory
,
endpointMediaTypes
,
(
id
)
->
id
);
endpointMediaTypes
,
(
id
)
->
id
);
return
new
CloudFoundryWebFluxEndpointHandlerMapping
(
return
new
CloudFoundryWebFluxEndpointHandlerMapping
(
new
EndpointMapping
(
"/cloudfoundryapplication"
),
new
EndpointMapping
(
"/cloudfoundryapplication"
),
endpointDiscoverer
.
discoverEndpoints
(),
endpointMediaTypes
,
getCorsConfiguration
(),
getSecurityInterceptor
(
webClientBuilder
,
environment
));
endpointDiscoverer
.
discoverEndpoints
(),
endpointMediaTypes
,
getCorsConfiguration
(),
getSecurityInterceptor
(
webClientBuilder
,
environment
));
}
}
private
ReactiveCloudFoundrySecurityInterceptor
getSecurityInterceptor
(
private
ReactiveCloudFoundrySecurityInterceptor
getSecurityInterceptor
(
...
@@ -91,8 +94,7 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration {
...
@@ -91,8 +94,7 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration {
private
ReactiveCloudFoundrySecurityService
getCloudFoundrySecurityService
(
private
ReactiveCloudFoundrySecurityService
getCloudFoundrySecurityService
(
WebClient
.
Builder
webClientBuilder
,
Environment
environment
)
{
WebClient
.
Builder
webClientBuilder
,
Environment
environment
)
{
String
cloudControllerUrl
=
environment
String
cloudControllerUrl
=
environment
.
getProperty
(
"vcap.application.cf_api"
);
.
getProperty
(
"vcap.application.cf_api"
);
return
(
cloudControllerUrl
==
null
?
null
return
(
cloudControllerUrl
==
null
?
null
:
new
ReactiveCloudFoundrySecurityService
(
webClientBuilder
,
:
new
ReactiveCloudFoundrySecurityService
(
webClientBuilder
,
cloudControllerUrl
));
cloudControllerUrl
));
...
@@ -111,30 +113,38 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration {
...
@@ -111,30 +113,38 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration {
@Configuration
@Configuration
@ConditionalOnClass
(
MatcherSecurityWebFilterChain
.
class
)
@ConditionalOnClass
(
MatcherSecurityWebFilterChain
.
class
)
static
class
IgnoredPathsSecurityConfiguration
{
static
class
IgnoredPathsSecurityConfiguration
{
@Bean
@Bean
public
BeanPostProcessor
webFilterChainPostProcessor
()
{
public
WebFilterChainPostProcessor
webFilterChainPostProcessor
()
{
return
new
BeanPostProcessor
()
{
return
new
WebFilterChainPostProcessor
();
}
}
private
static
class
WebFilterChainPostProcessor
implements
BeanPostProcessor
{
@Override
@Override
public
Object
postProcessAfterInitialization
(
Object
bean
,
String
beanName
)
throws
BeansException
{
public
Object
postProcessAfterInitialization
(
Object
bean
,
String
beanName
)
throws
BeansException
{
if
(
bean
instanceof
WebFilterChainProxy
)
{
if
(
bean
instanceof
WebFilterChainProxy
)
{
return
postProcess
((
WebFilterChainProxy
)
bean
);
return
postProcess
((
WebFilterChainProxy
)
bean
);
}
}
return
bean
;
return
bean
;
}
}
};
}
WebFilterChainProxy
postProcess
(
WebFilterChainProxy
existing
)
{
private
WebFilterChainProxy
postProcess
(
WebFilterChainProxy
existing
)
{
ServerWebExchangeMatcher
cloudFoundryRequestMatcher
=
ServerWebExchangeMatchers
.
pathMatchers
(
ServerWebExchangeMatcher
cloudFoundryRequestMatcher
=
ServerWebExchangeMatchers
"/cloudfoundryapplication/**"
);
.
pathMatchers
(
"/cloudfoundryapplication/**"
);
WebFilter
noOpFilter
=
(
exchange
,
chain
)
->
chain
.
filter
(
exchange
);
WebFilter
noOpFilter
=
(
exchange
,
chain
)
->
chain
.
filter
(
exchange
);
MatcherSecurityWebFilterChain
ignoredRequestFilterChain
=
new
MatcherSecurityWebFilterChain
(
MatcherSecurityWebFilterChain
ignoredRequestFilterChain
=
new
MatcherSecurityWebFilterChain
(
cloudFoundryRequestMatcher
,
Collections
.
singletonList
(
noOpFilter
));
cloudFoundryRequestMatcher
,
Collections
.
singletonList
(
noOpFilter
));
MatcherSecurityWebFilterChain
allRequestsFilterChain
=
new
MatcherSecurityWebFilterChain
(
MatcherSecurityWebFilterChain
allRequestsFilterChain
=
new
MatcherSecurityWebFilterChain
(
ServerWebExchangeMatchers
.
anyExchange
(),
Collections
.
singletonList
(
existing
));
ServerWebExchangeMatchers
.
anyExchange
(),
return
new
WebFilterChainProxy
(
ignoredRequestFilterChain
,
allRequestsFilterChain
);
Collections
.
singletonList
(
existing
));
return
new
WebFilterChainProxy
(
ignoredRequestFilterChain
,
allRequestsFilterChain
);
}
}
}
}
}
}
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundrySecurityInterceptor.java
View file @
3f00ba3c
...
@@ -63,28 +63,31 @@ class ReactiveCloudFoundrySecurityInterceptor {
...
@@ -63,28 +63,31 @@ class ReactiveCloudFoundrySecurityInterceptor {
}
}
if
(!
StringUtils
.
hasText
(
this
.
applicationId
))
{
if
(!
StringUtils
.
hasText
(
this
.
applicationId
))
{
return
Mono
.
error
(
new
CloudFoundryAuthorizationException
(
return
Mono
.
error
(
new
CloudFoundryAuthorizationException
(
Reason
.
SERVICE_UNAVAILABLE
,
Reason
.
SERVICE_UNAVAILABLE
,
"Application id is not available"
));
"Application id is not available"
));
}
}
if
(
this
.
cloudFoundrySecurityService
==
null
)
{
if
(
this
.
cloudFoundrySecurityService
==
null
)
{
return
Mono
.
error
(
new
CloudFoundryAuthorizationException
(
return
Mono
.
error
(
new
CloudFoundryAuthorizationException
(
Reason
.
SERVICE_UNAVAILABLE
,
Reason
.
SERVICE_UNAVAILABLE
,
"Cloud controller URL is not available"
));
"Cloud controller URL is not available"
));
}
}
return
check
(
exchange
,
endpointId
)
return
check
(
exchange
,
endpointId
).
then
(
SUCCESS
).
doOnError
(
this
::
logError
)
.
then
(
SUCCESS
)
.
doOnError
(
throwable
->
logger
.
error
(
throwable
.
getMessage
(),
throwable
))
.
onErrorResume
(
this
::
getErrorResponse
);
.
onErrorResume
(
this
::
getErrorResponse
);
}
}
private
void
logError
(
Throwable
ex
)
{
logger
.
error
(
ex
.
getMessage
(),
ex
);
}
private
Mono
<
Void
>
check
(
ServerWebExchange
exchange
,
String
path
)
{
private
Mono
<
Void
>
check
(
ServerWebExchange
exchange
,
String
path
)
{
try
{
try
{
Token
token
=
getToken
(
exchange
.
getRequest
());
Token
token
=
getToken
(
exchange
.
getRequest
());
return
this
.
tokenValidator
.
validate
(
token
).
then
(
this
.
cloudFoundrySecurityService
.
getAccessLevel
(
token
.
toString
(),
this
.
applicationId
))
return
this
.
tokenValidator
.
validate
(
token
)
.
filter
(
accessLevel
->
accessLevel
.
isAccessAllowed
(
path
))
.
then
(
this
.
cloudFoundrySecurityService
.
switchIfEmpty
(
Mono
.
error
(
new
CloudFoundryAuthorizationException
(
Reason
.
ACCESS_DENIED
,
.
getAccessLevel
(
token
.
toString
(),
this
.
applicationId
))
"Access denied"
)))
.
filter
((
accessLevel
)
->
accessLevel
.
isAccessAllowed
(
path
))
.
doOnSuccess
(
accessLevel
->
exchange
.
getAttributes
().
put
(
"cloudFoundryAccessLevel"
,
accessLevel
))
.
switchIfEmpty
(
Mono
.
error
(
new
CloudFoundryAuthorizationException
(
Reason
.
ACCESS_DENIED
,
"Access denied"
)))
.
doOnSuccess
((
accessLevel
)
->
exchange
.
getAttributes
()
.
put
(
"cloudFoundryAccessLevel"
,
accessLevel
))
.
then
();
.
then
();
}
}
catch
(
CloudFoundryAuthorizationException
ex
)
{
catch
(
CloudFoundryAuthorizationException
ex
)
{
...
@@ -107,8 +110,7 @@ class ReactiveCloudFoundrySecurityInterceptor {
...
@@ -107,8 +110,7 @@ class ReactiveCloudFoundrySecurityInterceptor {
String
bearerPrefix
=
"bearer "
;
String
bearerPrefix
=
"bearer "
;
if
(
authorization
==
null
if
(
authorization
==
null
||
!
authorization
.
toLowerCase
().
startsWith
(
bearerPrefix
))
{
||
!
authorization
.
toLowerCase
().
startsWith
(
bearerPrefix
))
{
throw
new
CloudFoundryAuthorizationException
(
throw
new
CloudFoundryAuthorizationException
(
Reason
.
MISSING_AUTHORIZATION
,
Reason
.
MISSING_AUTHORIZATION
,
"Authorization header is missing or invalid"
);
"Authorization header is missing or invalid"
);
}
}
return
new
Token
(
authorization
.
substring
(
bearerPrefix
.
length
()));
return
new
Token
(
authorization
.
substring
(
bearerPrefix
.
length
()));
...
...
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundrySecurityService.java
View file @
3f00ba3c
...
@@ -29,14 +29,19 @@ import org.springframework.core.ParameterizedTypeReference;
...
@@ -29,14 +29,19 @@ import org.springframework.core.ParameterizedTypeReference;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.util.Assert
;
import
org.springframework.util.Assert
;
import
org.springframework.web.reactive.function.client.WebClient
;
import
org.springframework.web.reactive.function.client.WebClient
;
import
org.springframework.web.reactive.function.client.WebClient.RequestHeadersSpec
;
import
org.springframework.web.reactive.function.client.WebClientResponseException
;
import
org.springframework.web.reactive.function.client.WebClientResponseException
;
/**
/**
* Reactive Cloud Foundry security service to handle REST calls to the cloud controller and UAA.
* Reactive Cloud Foundry security service to handle REST calls to the cloud controller
* and UAA.
*
*
* @author Madhura Bhave
* @author Madhura Bhave
*/
*/
public
class
ReactiveCloudFoundrySecurityService
{
class
ReactiveCloudFoundrySecurityService
{
private
static
final
ParameterizedTypeReference
<
Map
<
String
,
Object
>>
STRING_OBJECT_MAP
=
new
ParameterizedTypeReference
<
Map
<
String
,
Object
>>()
{
};
private
final
WebClient
webClient
;
private
final
WebClient
webClient
;
...
@@ -62,13 +67,15 @@ public class ReactiveCloudFoundrySecurityService {
...
@@ -62,13 +67,15 @@ public class ReactiveCloudFoundrySecurityService {
public
Mono
<
AccessLevel
>
getAccessLevel
(
String
token
,
String
applicationId
)
public
Mono
<
AccessLevel
>
getAccessLevel
(
String
token
,
String
applicationId
)
throws
CloudFoundryAuthorizationException
{
throws
CloudFoundryAuthorizationException
{
String
uri
=
getPermissionsUri
(
applicationId
);
String
uri
=
getPermissionsUri
(
applicationId
);
return
this
.
webClient
.
get
().
uri
(
uri
)
return
this
.
webClient
.
get
().
uri
(
uri
).
header
(
"Authorization"
,
"bearer "
+
token
)
.
header
(
"Authorization"
,
"bearer "
+
token
)
.
retrieve
().
bodyToMono
(
Map
.
class
).
map
(
this
::
getAccessLevel
)
.
retrieve
().
bodyToMono
(
Map
.
class
)
.
onErrorMap
(
this
::
mapError
);
.
map
(
this
::
getAccessLevel
)
}
.
onErrorMap
(
throwable
->
{
private
Throwable
mapError
(
Throwable
throwable
)
{
if
(
throwable
instanceof
WebClientResponseException
)
{
if
(
throwable
instanceof
WebClientResponseException
)
{
HttpStatus
statusCode
=
((
WebClientResponseException
)
throwable
).
getStatusCode
();
HttpStatus
statusCode
=
((
WebClientResponseException
)
throwable
)
.
getStatusCode
();
if
(
statusCode
.
equals
(
HttpStatus
.
FORBIDDEN
))
{
if
(
statusCode
.
equals
(
HttpStatus
.
FORBIDDEN
))
{
return
new
CloudFoundryAuthorizationException
(
Reason
.
ACCESS_DENIED
,
return
new
CloudFoundryAuthorizationException
(
Reason
.
ACCESS_DENIED
,
"Access denied"
);
"Access denied"
);
...
@@ -80,10 +87,9 @@ public class ReactiveCloudFoundrySecurityService {
...
@@ -80,10 +87,9 @@ public class ReactiveCloudFoundrySecurityService {
}
}
return
new
CloudFoundryAuthorizationException
(
Reason
.
SERVICE_UNAVAILABLE
,
return
new
CloudFoundryAuthorizationException
(
Reason
.
SERVICE_UNAVAILABLE
,
"Cloud controller not reachable"
);
"Cloud controller not reachable"
);
});
}
}
private
AccessLevel
getAccessLevel
(
Map
body
)
{
private
AccessLevel
getAccessLevel
(
Map
<?,
?>
body
)
{
if
(
Boolean
.
TRUE
.
equals
(
body
.
get
(
"read_sensitive_data"
)))
{
if
(
Boolean
.
TRUE
.
equals
(
body
.
get
(
"read_sensitive_data"
)))
{
return
AccessLevel
.
FULL
;
return
AccessLevel
.
FULL
;
}
}
...
@@ -91,8 +97,7 @@ public class ReactiveCloudFoundrySecurityService {
...
@@ -91,8 +97,7 @@ public class ReactiveCloudFoundrySecurityService {
}
}
private
String
getPermissionsUri
(
String
applicationId
)
{
private
String
getPermissionsUri
(
String
applicationId
)
{
return
this
.
cloudControllerUrl
+
"/v2/apps/"
+
applicationId
return
this
.
cloudControllerUrl
+
"/v2/apps/"
+
applicationId
+
"/permissions"
;
+
"/permissions"
;
}
}
/**
/**
...
@@ -100,14 +105,14 @@ public class ReactiveCloudFoundrySecurityService {
...
@@ -100,14 +105,14 @@ public class ReactiveCloudFoundrySecurityService {
* @return a Mono of token keys
* @return a Mono of token keys
*/
*/
public
Mono
<
Map
<
String
,
String
>>
fetchTokenKeys
()
{
public
Mono
<
Map
<
String
,
String
>>
fetchTokenKeys
()
{
return
getUaaUrl
()
return
getUaaUrl
().
flatMap
(
this
::
fetchTokenKeys
);
.
flatMap
(
url
->
this
.
webClient
.
get
()
}
.
uri
(
url
+
"/token_keys"
)
.
retrieve
().
bodyToMono
(
new
ParameterizedTypeReference
<
Map
<
String
,
Object
>>()
{
})
.
map
(
this
::
extractTokenKeys
)
.
onErrorMap
((
throwable
->
new
CloudFoundryAuthorizationException
(
Reason
.
SERVICE_UNAVAILABLE
,
throwable
.
getMessage
()))));
private
Mono
<?
extends
Map
<
String
,
String
>>
fetchTokenKeys
(
String
url
)
{
RequestHeadersSpec
<?>
uri
=
this
.
webClient
.
get
().
uri
(
url
+
"/token_keys"
);
return
uri
.
retrieve
().
bodyToMono
(
STRING_OBJECT_MAP
).
map
(
this
::
extractTokenKeys
)
.
onErrorMap
(((
ex
)
->
new
CloudFoundryAuthorizationException
(
Reason
.
SERVICE_UNAVAILABLE
,
ex
.
getMessage
())));
}
}
private
Map
<
String
,
String
>
extractTokenKeys
(
Map
<
String
,
Object
>
response
)
{
private
Map
<
String
,
String
>
extractTokenKeys
(
Map
<
String
,
Object
>
response
)
{
...
@@ -124,11 +129,11 @@ public class ReactiveCloudFoundrySecurityService {
...
@@ -124,11 +129,11 @@ public class ReactiveCloudFoundrySecurityService {
* @return the UAA url Mono
* @return the UAA url Mono
*/
*/
public
Mono
<
String
>
getUaaUrl
()
{
public
Mono
<
String
>
getUaaUrl
()
{
this
.
uaaUrl
=
this
.
webClient
this
.
uaaUrl
=
this
.
webClient
.
get
().
uri
(
this
.
cloudControllerUrl
+
"/info"
)
.
get
().
uri
(
this
.
cloudControllerUrl
+
"/info"
)
.
retrieve
().
bodyToMono
(
Map
.
class
)
.
retrieve
().
bodyToMono
(
Map
.
class
)
.
map
(
response
->
(
String
)
response
.
get
(
"token_endpoint"
)).
cache
()
.
map
((
response
)
->
(
String
)
response
.
get
(
"token_endpoint"
)).
cache
()
.
onErrorMap
(
throwable
->
new
CloudFoundryAuthorizationException
(
Reason
.
SERVICE_UNAVAILABLE
,
.
onErrorMap
((
ex
)
->
new
CloudFoundryAuthorizationException
(
Reason
.
SERVICE_UNAVAILABLE
,
"Unable to fetch token keys from UAA."
));
"Unable to fetch token keys from UAA."
));
return
this
.
uaaUrl
;
return
this
.
uaaUrl
;
}
}
...
...
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveTokenValidator.java
View file @
3f00ba3c
...
@@ -23,7 +23,6 @@ import java.security.PublicKey;
...
@@ -23,7 +23,6 @@ import java.security.PublicKey;
import
java.security.Signature
;
import
java.security.Signature
;
import
java.security.spec.InvalidKeySpecException
;
import
java.security.spec.InvalidKeySpecException
;
import
java.security.spec.X509EncodedKeySpec
;
import
java.security.spec.X509EncodedKeySpec
;
import
java.util.Map
;
import
java.util.concurrent.TimeUnit
;
import
java.util.concurrent.TimeUnit
;
import
reactor.core.publisher.Mono
;
import
reactor.core.publisher.Mono
;
...
@@ -38,27 +37,25 @@ import org.springframework.util.Base64Utils;
...
@@ -38,27 +37,25 @@ import org.springframework.util.Base64Utils;
*
*
* @author Madhura Bhave
* @author Madhura Bhave
*/
*/
public
class
ReactiveTokenValidator
{
class
ReactiveTokenValidator
{
private
final
ReactiveCloudFoundrySecurityService
securityService
;
private
final
ReactiveCloudFoundrySecurityService
securityService
;
public
ReactiveTokenValidator
(
ReactiveCloudFoundrySecurityService
securityService
)
{
ReactiveTokenValidator
(
ReactiveCloudFoundrySecurityService
securityService
)
{
this
.
securityService
=
securityService
;
this
.
securityService
=
securityService
;
}
}
public
Mono
<
Void
>
validate
(
Token
token
)
{
public
Mono
<
Void
>
validate
(
Token
token
)
{
return
validateAlgorithm
(
token
)
return
validateAlgorithm
(
token
).
then
(
validateKeyIdAndSignature
(
token
))
.
then
(
validateKeyIdAndSignature
(
token
))
.
then
(
validateExpiry
(
token
)).
then
(
validateIssuer
(
token
))
.
then
(
validateExpiry
(
token
))
.
then
(
validateIssuer
(
token
))
.
then
(
validateAudience
(
token
));
.
then
(
validateAudience
(
token
));
}
}
private
Mono
<
Void
>
validateAlgorithm
(
Token
token
)
{
private
Mono
<
Void
>
validateAlgorithm
(
Token
token
)
{
String
algorithm
=
token
.
getSignatureAlgorithm
();
String
algorithm
=
token
.
getSignatureAlgorithm
();
if
(
algorithm
==
null
)
{
if
(
algorithm
==
null
)
{
return
Mono
.
error
(
new
CloudFoundryAuthorizationException
(
Reason
.
INVALID_SIGNATURE
,
return
Mono
.
error
(
new
CloudFoundryAuthorizationException
(
"Signing algorithm cannot be null"
));
Reason
.
INVALID_SIGNATURE
,
"Signing algorithm cannot be null"
));
}
}
if
(!
algorithm
.
equals
(
"RS256"
))
{
if
(!
algorithm
.
equals
(
"RS256"
))
{
return
Mono
.
error
(
new
CloudFoundryAuthorizationException
(
return
Mono
.
error
(
new
CloudFoundryAuthorizationException
(
...
@@ -71,24 +68,16 @@ public class ReactiveTokenValidator {
...
@@ -71,24 +68,16 @@ public class ReactiveTokenValidator {
private
Mono
<
Void
>
validateKeyIdAndSignature
(
Token
token
)
{
private
Mono
<
Void
>
validateKeyIdAndSignature
(
Token
token
)
{
String
keyId
=
token
.
getKeyId
();
String
keyId
=
token
.
getKeyId
();
return
this
.
securityService
.
fetchTokenKeys
()
return
this
.
securityService
.
fetchTokenKeys
()
.
filter
(
tokenKeys
->
hasValidKeyId
(
keyId
,
tokenKeys
))
.
filter
(
tokenKeys
->
tokenKeys
.
containsKey
(
keyId
))
.
switchIfEmpty
(
Mono
.
error
(
new
CloudFoundryAuthorizationException
(
Reason
.
INVALID_KEY_ID
,
.
switchIfEmpty
(
Mono
.
error
(
new
CloudFoundryAuthorizationException
(
Reason
.
INVALID_KEY_ID
,
"Key Id present in token header does not match"
)))
"Key Id present in token header does not match"
)))
.
filter
(
tokenKeys
->
hasValidSignature
(
token
,
tokenKeys
.
get
(
keyId
)))
.
filter
(
tokenKeys
->
hasValidSignature
(
token
,
tokenKeys
.
get
(
keyId
)))
.
switchIfEmpty
(
Mono
.
error
(
new
CloudFoundryAuthorizationException
(
Reason
.
INVALID_SIGNATURE
,
.
switchIfEmpty
(
Mono
.
error
(
new
CloudFoundryAuthorizationException
(
"RSA Signature did not match content"
)))
Reason
.
INVALID_SIGNATURE
,
"RSA Signature did not match content"
)))
.
then
();
.
then
();
}
}
private
boolean
hasValidKeyId
(
String
keyId
,
Map
<
String
,
String
>
tokenKeys
)
{
for
(
String
candidate
:
tokenKeys
.
keySet
())
{
if
(
keyId
.
equals
(
candidate
))
{
return
true
;
}
}
return
false
;
}
private
boolean
hasValidSignature
(
Token
token
,
String
key
)
{
private
boolean
hasValidSignature
(
Token
token
,
String
key
)
{
try
{
try
{
PublicKey
publicKey
=
getPublicKey
(
key
);
PublicKey
publicKey
=
getPublicKey
(
key
);
...
@@ -123,17 +112,17 @@ public class ReactiveTokenValidator {
...
@@ -123,17 +112,17 @@ public class ReactiveTokenValidator {
private
Mono
<
Void
>
validateIssuer
(
Token
token
)
{
private
Mono
<
Void
>
validateIssuer
(
Token
token
)
{
return
this
.
securityService
.
getUaaUrl
()
return
this
.
securityService
.
getUaaUrl
()
.
map
(
uaaUrl
->
String
.
format
(
"%s/oauth/token"
,
uaaUrl
))
.
map
(
(
uaaUrl
)
->
String
.
format
(
"%s/oauth/token"
,
uaaUrl
))
.
filter
(
issuerUri
->
issuerUri
.
equals
(
token
.
getIssuer
()))
.
filter
(
(
issuerUri
)
->
issuerUri
.
equals
(
token
.
getIssuer
()))
.
switchIfEmpty
(
Mono
.
error
(
new
CloudFoundryAuthorizationException
(
Reason
.
INVALID_ISSUER
,
.
switchIfEmpty
(
Mono
.
error
(
new
CloudFoundryAuthorizationException
(
"Token issuer does not match"
)))
Reason
.
INVALID_ISSUER
,
"Token issuer does not match"
)))
.
then
();
.
then
();
}
}
private
Mono
<
Void
>
validateAudience
(
Token
token
)
{
private
Mono
<
Void
>
validateAudience
(
Token
token
)
{
if
(!
token
.
getScope
().
contains
(
"actuator.read"
))
{
if
(!
token
.
getScope
().
contains
(
"actuator.read"
))
{
return
Mono
.
error
(
new
CloudFoundryAuthorizationException
(
Reason
.
INVALID_AUDIENCE
,
return
Mono
.
error
(
new
CloudFoundryAuthorizationException
(
"Token does not have audience actuator"
));
Reason
.
INVALID_AUDIENCE
,
"Token does not have audience actuator"
));
}
}
return
Mono
.
empty
();
return
Mono
.
empty
();
}
}
...
...
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryActuatorAutoConfiguration.java
View file @
3f00ba3c
...
@@ -82,8 +82,7 @@ public class CloudFoundryActuatorAutoConfiguration {
...
@@ -82,8 +82,7 @@ public class CloudFoundryActuatorAutoConfiguration {
RestTemplateBuilder
restTemplateBuilder
,
Environment
environment
)
{
RestTemplateBuilder
restTemplateBuilder
,
Environment
environment
)
{
CloudFoundrySecurityService
cloudfoundrySecurityService
=
getCloudFoundrySecurityService
(
CloudFoundrySecurityService
cloudfoundrySecurityService
=
getCloudFoundrySecurityService
(
restTemplateBuilder
,
environment
);
restTemplateBuilder
,
environment
);
TokenValidator
tokenValidator
=
new
TokenValidator
(
TokenValidator
tokenValidator
=
new
TokenValidator
(
cloudfoundrySecurityService
);
cloudfoundrySecurityService
);
return
new
CloudFoundrySecurityInterceptor
(
tokenValidator
,
return
new
CloudFoundrySecurityInterceptor
(
tokenValidator
,
cloudfoundrySecurityService
,
cloudfoundrySecurityService
,
environment
.
getProperty
(
"vcap.application.application_id"
));
environment
.
getProperty
(
"vcap.application.application_id"
));
...
@@ -91,13 +90,12 @@ public class CloudFoundryActuatorAutoConfiguration {
...
@@ -91,13 +90,12 @@ public class CloudFoundryActuatorAutoConfiguration {
private
CloudFoundrySecurityService
getCloudFoundrySecurityService
(
private
CloudFoundrySecurityService
getCloudFoundrySecurityService
(
RestTemplateBuilder
restTemplateBuilder
,
Environment
environment
)
{
RestTemplateBuilder
restTemplateBuilder
,
Environment
environment
)
{
String
cloudControllerUrl
=
environment
String
cloudControllerUrl
=
environment
.
getProperty
(
"vcap.application.cf_api"
);
.
getProperty
(
"vcap.application.cf_api"
);
boolean
skipSslValidation
=
environment
.
getProperty
(
boolean
skipSslValidation
=
environment
.
getProperty
(
"management.cloudfoundry.skip-ssl-validation"
,
Boolean
.
class
,
false
);
"management.cloudfoundry.skip-ssl-validation"
,
Boolean
.
class
,
false
);
return
(
cloudControllerUrl
==
null
?
null
return
(
cloudControllerUrl
==
null
?
null
:
new
CloudFoundrySecurityService
(
restTemplateBuilder
,
:
new
CloudFoundrySecurityService
(
restTemplateBuilder
,
cloudControllerUrl
,
cloudControllerUrl
,
skipSslValidation
));
skipSslValidation
));
}
}
private
CorsConfiguration
getCorsConfiguration
()
{
private
CorsConfiguration
getCorsConfiguration
()
{
...
...
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundrySecurityInterceptor.java
View file @
3f00ba3c
...
@@ -63,13 +63,11 @@ class CloudFoundrySecurityInterceptor {
...
@@ -63,13 +63,11 @@ class CloudFoundrySecurityInterceptor {
}
}
try
{
try
{
if
(!
StringUtils
.
hasText
(
this
.
applicationId
))
{
if
(!
StringUtils
.
hasText
(
this
.
applicationId
))
{
throw
new
CloudFoundryAuthorizationException
(
throw
new
CloudFoundryAuthorizationException
(
Reason
.
SERVICE_UNAVAILABLE
,
Reason
.
SERVICE_UNAVAILABLE
,
"Application id is not available"
);
"Application id is not available"
);
}
}
if
(
this
.
cloudFoundrySecurityService
==
null
)
{
if
(
this
.
cloudFoundrySecurityService
==
null
)
{
throw
new
CloudFoundryAuthorizationException
(
throw
new
CloudFoundryAuthorizationException
(
Reason
.
SERVICE_UNAVAILABLE
,
Reason
.
SERVICE_UNAVAILABLE
,
"Cloud controller URL is not available"
);
"Cloud controller URL is not available"
);
}
}
if
(
HttpMethod
.
OPTIONS
.
matches
(
request
.
getMethod
()))
{
if
(
HttpMethod
.
OPTIONS
.
matches
(
request
.
getMethod
()))
{
...
@@ -96,8 +94,7 @@ class CloudFoundrySecurityInterceptor {
...
@@ -96,8 +94,7 @@ class CloudFoundrySecurityInterceptor {
AccessLevel
accessLevel
=
this
.
cloudFoundrySecurityService
AccessLevel
accessLevel
=
this
.
cloudFoundrySecurityService
.
getAccessLevel
(
token
.
toString
(),
this
.
applicationId
);
.
getAccessLevel
(
token
.
toString
(),
this
.
applicationId
);
if
(!
accessLevel
.
isAccessAllowed
(
path
))
{
if
(!
accessLevel
.
isAccessAllowed
(
path
))
{
throw
new
CloudFoundryAuthorizationException
(
throw
new
CloudFoundryAuthorizationException
(
Reason
.
ACCESS_DENIED
,
Reason
.
ACCESS_DENIED
,
"Access denied"
);
"Access denied"
);
}
}
request
.
setAttribute
(
AccessLevel
.
REQUEST_ATTRIBUTE
,
accessLevel
);
request
.
setAttribute
(
AccessLevel
.
REQUEST_ATTRIBUTE
,
accessLevel
);
...
@@ -108,8 +105,7 @@ class CloudFoundrySecurityInterceptor {
...
@@ -108,8 +105,7 @@ class CloudFoundrySecurityInterceptor {
String
bearerPrefix
=
"bearer "
;
String
bearerPrefix
=
"bearer "
;
if
(
authorization
==
null
if
(
authorization
==
null
||
!
authorization
.
toLowerCase
().
startsWith
(
bearerPrefix
))
{
||
!
authorization
.
toLowerCase
().
startsWith
(
bearerPrefix
))
{
throw
new
CloudFoundryAuthorizationException
(
throw
new
CloudFoundryAuthorizationException
(
Reason
.
MISSING_AUTHORIZATION
,
Reason
.
MISSING_AUTHORIZATION
,
"Authorization header is missing or invalid"
);
"Authorization header is missing or invalid"
);
}
}
return
new
Token
(
authorization
.
substring
(
bearerPrefix
.
length
()));
return
new
Token
(
authorization
.
substring
(
bearerPrefix
.
length
()));
...
...
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundryWebEndpointServletHandlerMapping.java
View file @
3f00ba3c
...
@@ -93,12 +93,13 @@ class CloudFoundryWebEndpointServletHandlerMapping
...
@@ -93,12 +93,13 @@ class CloudFoundryWebEndpointServletHandlerMapping
@ResponseBody
@ResponseBody
private
Map
<
String
,
Map
<
String
,
Link
>>
links
(
HttpServletRequest
request
,
private
Map
<
String
,
Map
<
String
,
Link
>>
links
(
HttpServletRequest
request
,
HttpServletResponse
response
)
{
HttpServletResponse
response
)
{
SecurityResponse
securityResponse
=
this
.
securityInterceptor
SecurityResponse
securityResponse
=
this
.
securityInterceptor
.
preHandle
(
request
,
.
preHandle
(
request
,
""
);
""
);
if
(!
securityResponse
.
getStatus
().
equals
(
HttpStatus
.
OK
))
{
if
(!
securityResponse
.
getStatus
().
equals
(
HttpStatus
.
OK
))
{
sendFailureResponse
(
response
,
securityResponse
);
sendFailureResponse
(
response
,
securityResponse
);
}
}
AccessLevel
accessLevel
=
(
AccessLevel
)
request
.
getAttribute
(
AccessLevel
.
REQUEST_ATTRIBUTE
);
AccessLevel
accessLevel
=
(
AccessLevel
)
request
.
getAttribute
(
AccessLevel
.
REQUEST_ATTRIBUTE
);
Map
<
String
,
Link
>
links
=
this
.
endpointLinksResolver
.
resolveLinks
(
getEndpoints
(),
Map
<
String
,
Link
>
links
=
this
.
endpointLinksResolver
.
resolveLinks
(
getEndpoints
(),
request
.
getRequestURL
().
toString
());
request
.
getRequestURL
().
toString
());
Map
<
String
,
Link
>
filteredLinks
=
new
LinkedHashMap
<>();
Map
<
String
,
Link
>
filteredLinks
=
new
LinkedHashMap
<>();
...
@@ -174,8 +175,7 @@ class CloudFoundryWebEndpointServletHandlerMapping
...
@@ -174,8 +175,7 @@ class CloudFoundryWebEndpointServletHandlerMapping
}
}
}
}
private
Object
failureResponse
(
private
Object
failureResponse
(
SecurityResponse
response
)
{
SecurityResponse
response
)
{
return
handleResult
(
new
WebEndpointResponse
<>(
response
.
getMessage
(),
return
handleResult
(
new
WebEndpointResponse
<>(
response
.
getMessage
(),
response
.
getStatus
().
value
()));
response
.
getStatus
().
value
()));
}
}
...
...
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/TokenValidator.java
View file @
3f00ba3c
...
@@ -36,13 +36,13 @@ import org.springframework.util.Base64Utils;
...
@@ -36,13 +36,13 @@ import org.springframework.util.Base64Utils;
*
*
* @author Madhura Bhave
* @author Madhura Bhave
*/
*/
public
class
TokenValidator
{
class
TokenValidator
{
private
final
CloudFoundrySecurityService
securityService
;
private
final
CloudFoundrySecurityService
securityService
;
private
Map
<
String
,
String
>
tokenKeys
;
private
Map
<
String
,
String
>
tokenKeys
;
public
TokenValidator
(
CloudFoundrySecurityService
cloudFoundrySecurityService
)
{
TokenValidator
(
CloudFoundrySecurityService
cloudFoundrySecurityService
)
{
this
.
securityService
=
cloudFoundrySecurityService
;
this
.
securityService
=
cloudFoundrySecurityService
;
}
}
...
...
spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/CloudFoundryWebFluxEndpointIntegrationTests.java
View file @
3f00ba3c
...
@@ -23,7 +23,6 @@ import java.util.function.BiConsumer;
...
@@ -23,7 +23,6 @@ import java.util.function.BiConsumer;
import
java.util.function.Consumer
;
import
java.util.function.Consumer
;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.mockito.BDDMockito
;
import
reactor.core.publisher.Mono
;
import
reactor.core.publisher.Mono
;
import
org.springframework.boot.actuate.autoconfigure.cloudfoundry.AccessLevel
;
import
org.springframework.boot.actuate.autoconfigure.cloudfoundry.AccessLevel
;
...
@@ -37,6 +36,7 @@ import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
...
@@ -37,6 +36,7 @@ import org.springframework.boot.actuate.endpoint.annotation.WriteOperation;
import
org.springframework.boot.actuate.endpoint.cache.CachingConfiguration
;
import
org.springframework.boot.actuate.endpoint.cache.CachingConfiguration
;
import
org.springframework.boot.actuate.endpoint.convert.ConversionServiceParameterMapper
;
import
org.springframework.boot.actuate.endpoint.convert.ConversionServiceParameterMapper
;
import
org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes
;
import
org.springframework.boot.actuate.endpoint.web.EndpointMediaTypes
;
import
org.springframework.boot.actuate.endpoint.web.EndpointPathResolver
;
import
org.springframework.boot.actuate.endpoint.web.annotation.WebAnnotationEndpointDiscoverer
;
import
org.springframework.boot.actuate.endpoint.web.annotation.WebAnnotationEndpointDiscoverer
;
import
org.springframework.boot.endpoint.web.EndpointMapping
;
import
org.springframework.boot.endpoint.web.EndpointMapping
;
import
org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory
;
import
org.springframework.boot.web.embedded.netty.NettyReactiveWebServerFactory
;
...
@@ -60,6 +60,7 @@ import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
...
@@ -60,6 +60,7 @@ import org.springframework.web.server.adapter.WebHttpHandlerBuilder;
import
static
org
.
mockito
.
ArgumentMatchers
.
any
;
import
static
org
.
mockito
.
ArgumentMatchers
.
any
;
import
static
org
.
mockito
.
ArgumentMatchers
.
eq
;
import
static
org
.
mockito
.
ArgumentMatchers
.
eq
;
import
static
org
.
mockito
.
BDDMockito
.
given
;
import
static
org
.
mockito
.
BDDMockito
.
given
;
import
static
org
.
mockito
.
BDDMockito
.
willThrow
;
import
static
org
.
mockito
.
Mockito
.
mock
;
import
static
org
.
mockito
.
Mockito
.
mock
;
/**
/**
...
@@ -69,7 +70,8 @@ import static org.mockito.Mockito.mock;
...
@@ -69,7 +70,8 @@ import static org.mockito.Mockito.mock;
*/
*/
public
class
CloudFoundryWebFluxEndpointIntegrationTests
{
public
class
CloudFoundryWebFluxEndpointIntegrationTests
{
private
static
ReactiveTokenValidator
tokenValidator
=
mock
(
ReactiveTokenValidator
.
class
);
private
static
ReactiveTokenValidator
tokenValidator
=
mock
(
ReactiveTokenValidator
.
class
);
private
static
ReactiveCloudFoundrySecurityService
securityService
=
mock
(
private
static
ReactiveCloudFoundrySecurityService
securityService
=
mock
(
ReactiveCloudFoundrySecurityService
.
class
);
ReactiveCloudFoundrySecurityService
.
class
);
...
@@ -137,7 +139,7 @@ public class CloudFoundryWebFluxEndpointIntegrationTests {
...
@@ -137,7 +139,7 @@ public class CloudFoundryWebFluxEndpointIntegrationTests {
public
void
linksToOtherEndpointsForbidden
()
{
public
void
linksToOtherEndpointsForbidden
()
{
CloudFoundryAuthorizationException
exception
=
new
CloudFoundryAuthorizationException
(
CloudFoundryAuthorizationException
exception
=
new
CloudFoundryAuthorizationException
(
Reason
.
INVALID_TOKEN
,
"invalid-token"
);
Reason
.
INVALID_TOKEN
,
"invalid-token"
);
BDDMockito
.
willThrow
(
exception
).
given
(
tokenValidator
).
validate
(
any
());
willThrow
(
exception
).
given
(
tokenValidator
).
validate
(
any
());
load
(
TestEndpointConfiguration
.
class
,
load
(
TestEndpointConfiguration
.
class
,
(
client
)
->
client
.
get
().
uri
(
"/cfApplication"
)
(
client
)
->
client
.
get
().
uri
(
"/cfApplication"
)
.
accept
(
MediaType
.
APPLICATION_JSON
)
.
accept
(
MediaType
.
APPLICATION_JSON
)
...
@@ -203,8 +205,8 @@ public class CloudFoundryWebFluxEndpointIntegrationTests {
...
@@ -203,8 +205,8 @@ public class CloudFoundryWebFluxEndpointIntegrationTests {
@Bean
@Bean
public
ReactiveCloudFoundrySecurityInterceptor
interceptor
()
{
public
ReactiveCloudFoundrySecurityInterceptor
interceptor
()
{
return
new
ReactiveCloudFoundrySecurityInterceptor
(
tokenValidator
,
securityService
,
return
new
ReactiveCloudFoundrySecurityInterceptor
(
tokenValidator
,
"app-id"
);
securityService
,
"app-id"
);
}
}
@Bean
@Bean
...
@@ -235,7 +237,7 @@ public class CloudFoundryWebFluxEndpointIntegrationTests {
...
@@ -235,7 +237,7 @@ public class CloudFoundryWebFluxEndpointIntegrationTests {
DefaultConversionService
.
getSharedInstance
());
DefaultConversionService
.
getSharedInstance
());
return
new
WebAnnotationEndpointDiscoverer
(
applicationContext
,
return
new
WebAnnotationEndpointDiscoverer
(
applicationContext
,
parameterMapper
,
(
id
)
->
new
CachingConfiguration
(
0
),
parameterMapper
,
(
id
)
->
new
CachingConfiguration
(
0
),
endpointMediaTypes
,
(
id
)
->
id
);
endpointMediaTypes
,
EndpointPathResolver
.
useEndpointId
()
);
}
}
@Bean
@Bean
...
...
spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundryActuatorAutoConfigurationTests.java
View file @
3f00ba3c
...
@@ -80,9 +80,9 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests {
...
@@ -80,9 +80,9 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests {
setupContextWithCloudEnabled
();
setupContextWithCloudEnabled
();
this
.
context
.
refresh
();
this
.
context
.
refresh
();
CloudFoundryWebFluxEndpointHandlerMapping
handlerMapping
=
getHandlerMapping
();
CloudFoundryWebFluxEndpointHandlerMapping
handlerMapping
=
getHandlerMapping
();
EndpointMapping
endpointMapping
=
(
EndpointMapping
)
ReflectionTestUtils
.
getField
(
handlerMapping
,
"endpointMapping"
);
EndpointMapping
endpointMapping
=
(
EndpointMapping
)
ReflectionTestUtils
assertThat
(
endpointMapping
.
getPath
())
.
getField
(
handlerMapping
,
"endpointMapping"
);
.
isEqualTo
(
"/cloudfoundryapplication"
);
assertThat
(
endpointMapping
.
getPath
())
.
isEqualTo
(
"/cloudfoundryapplication"
);
CorsConfiguration
corsConfiguration
=
(
CorsConfiguration
)
ReflectionTestUtils
CorsConfiguration
corsConfiguration
=
(
CorsConfiguration
)
ReflectionTestUtils
.
getField
(
handlerMapping
,
"corsConfiguration"
);
.
getField
(
handlerMapping
,
"corsConfiguration"
);
assertThat
(
corsConfiguration
.
getAllowedOrigins
()).
contains
(
"*"
);
assertThat
(
corsConfiguration
.
getAllowedOrigins
()).
contains
(
"*"
);
...
@@ -96,9 +96,10 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests {
...
@@ -96,9 +96,10 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests {
public
void
cloudfoundryapplicationProducesActuatorMediaType
()
throws
Exception
{
public
void
cloudfoundryapplicationProducesActuatorMediaType
()
throws
Exception
{
setupContextWithCloudEnabled
();
setupContextWithCloudEnabled
();
this
.
context
.
refresh
();
this
.
context
.
refresh
();
WebTestClient
webTestClient
=
WebTestClient
.
bindToApplicationContext
(
this
.
context
).
build
();
WebTestClient
webTestClient
=
WebTestClient
.
bindToApplicationContext
(
this
.
context
)
webTestClient
.
get
().
uri
(
"/cloudfoundryapplication"
)
.
build
();
.
header
(
"Content-Type"
,
ActuatorMediaType
.
V2_JSON
+
";charset=UTF-8"
);
webTestClient
.
get
().
uri
(
"/cloudfoundryapplication"
).
header
(
"Content-Type"
,
ActuatorMediaType
.
V2_JSON
+
";charset=UTF-8"
);
}
}
@Test
@Test
...
@@ -135,7 +136,8 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests {
...
@@ -135,7 +136,8 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests {
.
applyTo
(
this
.
context
);
.
applyTo
(
this
.
context
);
setupContext
();
setupContext
();
this
.
context
.
refresh
();
this
.
context
.
refresh
();
CloudFoundryWebFluxEndpointHandlerMapping
handlerMapping
=
this
.
context
.
getBean
(
"cloudFoundryWebFluxEndpointHandlerMapping"
,
CloudFoundryWebFluxEndpointHandlerMapping
handlerMapping
=
this
.
context
.
getBean
(
"cloudFoundryWebFluxEndpointHandlerMapping"
,
CloudFoundryWebFluxEndpointHandlerMapping
.
class
);
CloudFoundryWebFluxEndpointHandlerMapping
.
class
);
Object
securityInterceptor
=
ReflectionTestUtils
.
getField
(
handlerMapping
,
Object
securityInterceptor
=
ReflectionTestUtils
.
getField
(
handlerMapping
,
"securityInterceptor"
);
"securityInterceptor"
);
...
@@ -145,20 +147,26 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests {
...
@@ -145,20 +147,26 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests {
}
}
@Test
@Test
@SuppressWarnings
(
"unchecked"
)
public
void
cloudFoundryPathsIgnoredBySpringSecurity
()
throws
Exception
{
public
void
cloudFoundryPathsIgnoredBySpringSecurity
()
throws
Exception
{
setupContextWithCloudEnabled
();
setupContextWithCloudEnabled
();
this
.
context
.
refresh
();
this
.
context
.
refresh
();
WebFilterChainProxy
chainProxy
=
this
.
context
WebFilterChainProxy
chainProxy
=
this
.
context
.
getBean
(
WebFilterChainProxy
.
class
);
.
getBean
(
WebFilterChainProxy
.
class
);
List
<
SecurityWebFilterChain
>
filters
=
(
List
<
SecurityWebFilterChain
>)
ReflectionTestUtils
List
<
SecurityWebFilterChain
>
filters
=
(
List
<
SecurityWebFilterChain
>)
ReflectionTestUtils
.
getField
(
chainProxy
,
"filters"
);
.
getField
(
chainProxy
,
"filters"
);
Boolean
cfRequestMatches
=
filters
.
get
(
0
).
matches
(
MockServerWebExchange
.
from
(
Boolean
cfRequestMatches
=
filters
.
get
(
0
).
matches
(
MockServerWebExchange
.
from
(
MockServerHttpRequest
.
get
(
"/cloudfoundryapplication/my-path"
).
build
())).
block
();
MockServerHttpRequest
.
get
(
"/cloudfoundryapplication/my-path"
).
build
()))
Boolean
otherRequestMatches
=
filters
.
get
(
0
).
matches
(
MockServerWebExchange
.
from
(
.
block
();
MockServerHttpRequest
.
get
(
"/some-other-path"
).
build
())).
block
();
Boolean
otherRequestMatches
=
filters
.
get
(
0
)
.
matches
(
MockServerWebExchange
.
from
(
MockServerHttpRequest
.
get
(
"/some-other-path"
).
build
()))
.
block
();
assertThat
(
cfRequestMatches
).
isTrue
();
assertThat
(
cfRequestMatches
).
isTrue
();
assertThat
(
otherRequestMatches
).
isFalse
();
assertThat
(
otherRequestMatches
).
isFalse
();
otherRequestMatches
=
filters
.
get
(
1
).
matches
(
MockServerWebExchange
.
from
(
otherRequestMatches
=
filters
.
get
(
1
)
MockServerHttpRequest
.
get
(
"/some-other-path"
).
build
())).
block
();
.
matches
(
MockServerWebExchange
.
from
(
MockServerHttpRequest
.
get
(
"/some-other-path"
).
build
()))
.
block
();
assertThat
(
otherRequestMatches
).
isTrue
();
assertThat
(
otherRequestMatches
).
isTrue
();
}
}
...
@@ -166,8 +174,7 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests {
...
@@ -166,8 +174,7 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests {
public
void
cloudFoundryPlatformInactive
()
throws
Exception
{
public
void
cloudFoundryPlatformInactive
()
throws
Exception
{
setupContext
();
setupContext
();
this
.
context
.
refresh
();
this
.
context
.
refresh
();
assertThat
(
assertThat
(
this
.
context
.
containsBean
(
"cloudFoundryWebFluxEndpointHandlerMapping"
))
this
.
context
.
containsBean
(
"cloudFoundryWebFluxEndpointHandlerMapping"
))
.
isFalse
();
.
isFalse
();
}
}
...
@@ -196,8 +203,7 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests {
...
@@ -196,8 +203,7 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests {
}
}
@Test
@Test
public
void
endpointPathCustomizationIsNotApplied
()
public
void
endpointPathCustomizationIsNotApplied
()
throws
Exception
{
throws
Exception
{
setupContextWithCloudEnabled
();
setupContextWithCloudEnabled
();
this
.
context
.
register
(
TestConfiguration
.
class
);
this
.
context
.
register
(
TestConfiguration
.
class
);
this
.
context
.
refresh
();
this
.
context
.
refresh
();
...
@@ -223,10 +229,8 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests {
...
@@ -223,10 +229,8 @@ public class ReactiveCloudFoundryActuatorAutoConfigurationTests {
WebFluxAutoConfiguration
.
class
,
JacksonAutoConfiguration
.
class
,
WebFluxAutoConfiguration
.
class
,
JacksonAutoConfiguration
.
class
,
HttpMessageConvertersAutoConfiguration
.
class
,
HttpMessageConvertersAutoConfiguration
.
class
,
PropertyPlaceholderAutoConfiguration
.
class
,
PropertyPlaceholderAutoConfiguration
.
class
,
WebClientCustomizerConfig
.
class
,
WebClientCustomizerConfig
.
class
,
WebClientAutoConfiguration
.
class
,
WebClientAutoConfiguration
.
class
,
ManagementContextAutoConfiguration
.
class
,
EndpointAutoConfiguration
.
class
,
ManagementContextAutoConfiguration
.
class
,
EndpointAutoConfiguration
.
class
,
ReactiveCloudFoundryActuatorAutoConfiguration
.
class
);
ReactiveCloudFoundryActuatorAutoConfiguration
.
class
);
}
}
...
...
spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundrySecurityInterceptorTests.java
View file @
3f00ba3c
...
@@ -18,7 +18,6 @@ package org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive;
...
@@ -18,7 +18,6 @@ package org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive;
import
org.junit.Before
;
import
org.junit.Before
;
import
org.junit.Test
;
import
org.junit.Test
;
import
org.mockito.BDDMockito
;
import
org.mockito.Mock
;
import
org.mockito.Mock
;
import
org.mockito.MockitoAnnotations
;
import
org.mockito.MockitoAnnotations
;
import
reactor.core.publisher.Mono
;
import
reactor.core.publisher.Mono
;
...
@@ -35,6 +34,7 @@ import org.springframework.util.Base64Utils;
...
@@ -35,6 +34,7 @@ import org.springframework.util.Base64Utils;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
import
static
org
.
mockito
.
ArgumentMatchers
.
any
;
import
static
org
.
mockito
.
ArgumentMatchers
.
any
;
import
static
org
.
mockito
.
BDDMockito
.
given
;
/**
/**
* Tests for {@link ReactiveCloudFoundrySecurityInterceptor}.
* Tests for {@link ReactiveCloudFoundrySecurityInterceptor}.
...
@@ -54,55 +54,53 @@ public class ReactiveCloudFoundrySecurityInterceptorTests {
...
@@ -54,55 +54,53 @@ public class ReactiveCloudFoundrySecurityInterceptorTests {
@Before
@Before
public
void
setup
()
throws
Exception
{
public
void
setup
()
throws
Exception
{
MockitoAnnotations
.
initMocks
(
this
);
MockitoAnnotations
.
initMocks
(
this
);
this
.
interceptor
=
new
ReactiveCloudFoundrySecurityInterceptor
(
this
.
tokenValidator
,
this
.
interceptor
=
new
ReactiveCloudFoundrySecurityInterceptor
(
this
.
securityService
,
"my-app-id"
);
this
.
tokenValidator
,
this
.
securityService
,
"my-app-id"
);
}
}
@Test
@Test
public
void
preHandleWhenRequestIsPreFlightShouldBeOk
()
throws
Exception
{
public
void
preHandleWhenRequestIsPreFlightShouldBeOk
()
throws
Exception
{
MockServerWebExchange
request
=
MockServerWebExchange
MockServerWebExchange
request
=
MockServerWebExchange
.
from
(
MockServerHttpRequest
.
from
(
MockServerHttpRequest
.
options
(
"/a"
)
.
options
(
"/a"
).
header
(
HttpHeaders
.
ORIGIN
,
"http://example.com"
)
.
header
(
HttpHeaders
.
ORIGIN
,
"http://example.com"
)
.
header
(
HttpHeaders
.
ACCESS_CONTROL_REQUEST_METHOD
,
"GET"
).
build
());
.
header
(
HttpHeaders
.
ACCESS_CONTROL_REQUEST_METHOD
,
"GET"
)
StepVerifier
.
create
(
this
.
interceptor
.
preHandle
(
request
,
"/a"
)).
consumeNextWith
(
.
build
());
(
response
)
->
assertThat
(
response
.
getStatus
()).
isEqualTo
(
HttpStatus
.
OK
))
StepVerifier
.
create
(
this
.
interceptor
.
preHandle
(
request
,
"/a"
))
.
consumeNextWith
(
response
->
assertThat
(
response
.
getStatus
()).
isEqualTo
(
HttpStatus
.
OK
))
.
verifyComplete
();
.
verifyComplete
();
}
}
@Test
@Test
public
void
preHandleWhenTokenIsMissingShouldReturnMissingAuthorization
()
throws
Exception
{
public
void
preHandleWhenTokenIsMissingShouldReturnMissingAuthorization
()
throws
Exception
{
MockServerWebExchange
request
=
MockServerWebExchange
MockServerWebExchange
request
=
MockServerWebExchange
.
from
(
MockServerHttpRequest
.
get
(
"/a"
)
.
from
(
MockServerHttpRequest
.
get
(
"/a"
).
build
());
.
build
());
StepVerifier
.
create
(
this
.
interceptor
.
preHandle
(
request
,
"/a"
))
StepVerifier
.
create
(
this
.
interceptor
.
preHandle
(
request
,
"/a"
))
.
consumeNextWith
(
response
->
assertThat
(
response
.
getStatus
())
.
consumeNextWith
(
(
response
)
->
assertThat
(
response
.
getStatus
())
.
isEqualTo
(
Reason
.
MISSING_AUTHORIZATION
.
getStatus
()))
.
isEqualTo
(
Reason
.
MISSING_AUTHORIZATION
.
getStatus
()))
.
verifyComplete
();
.
verifyComplete
();
}
}
@Test
@Test
public
void
preHandleWhenTokenIsNotBearerShouldReturnMissingAuthorization
()
throws
Exception
{
public
void
preHandleWhenTokenIsNotBearerShouldReturnMissingAuthorization
()
MockServerWebExchange
request
=
MockServerWebExchange
throws
Exception
{
.
from
(
MockServerHttpRequest
.
get
(
"/a"
)
MockServerWebExchange
request
=
MockServerWebExchange
.
from
(
MockServerHttpRequest
.
header
(
HttpHeaders
.
AUTHORIZATION
,
mockAccessToken
())
.
get
(
"/a"
).
header
(
HttpHeaders
.
AUTHORIZATION
,
mockAccessToken
()).
build
());
.
build
());
StepVerifier
.
create
(
this
.
interceptor
.
preHandle
(
request
,
"/a"
))
StepVerifier
.
create
(
this
.
interceptor
.
preHandle
(
request
,
"/a"
))
.
consumeNextWith
(
response
->
assertThat
(
response
.
getStatus
())
.
consumeNextWith
(
(
response
)
->
assertThat
(
response
.
getStatus
())
.
isEqualTo
(
Reason
.
MISSING_AUTHORIZATION
.
getStatus
()))
.
isEqualTo
(
Reason
.
MISSING_AUTHORIZATION
.
getStatus
()))
.
verifyComplete
();
.
verifyComplete
();
}
}
@Test
@Test
public
void
preHandleWhenApplicationIdIsNullShouldReturnError
()
throws
Exception
{
public
void
preHandleWhenApplicationIdIsNullShouldReturnError
()
throws
Exception
{
this
.
interceptor
=
new
ReactiveCloudFoundrySecurityInterceptor
(
this
.
tokenValidator
,
this
.
interceptor
=
new
ReactiveCloudFoundrySecurityInterceptor
(
this
.
securityService
,
null
);
this
.
tokenValidator
,
this
.
securityService
,
null
);
MockServerWebExchange
request
=
MockServerWebExchange
MockServerWebExchange
request
=
MockServerWebExchange
.
from
(
MockServerHttpRequest
.
get
(
"/a"
)
.
from
(
MockServerHttpRequest
.
get
(
"/a"
)
.
header
(
HttpHeaders
.
AUTHORIZATION
,
"bearer "
+
mockAccessToken
())
.
header
(
HttpHeaders
.
AUTHORIZATION
,
"bearer "
+
mockAccessToken
())
.
build
());
.
build
());
StepVerifier
.
create
(
this
.
interceptor
.
preHandle
(
request
,
"/a"
))
StepVerifier
.
create
(
this
.
interceptor
.
preHandle
(
request
,
"/a"
))
.
consumeErrorWith
(
throwable
->
assertThat
(((
CloudFoundryAuthorizationException
)
throwable
).
getReason
())
.
consumeErrorWith
((
ex
)
->
assertThat
(
((
CloudFoundryAuthorizationException
)
ex
).
getReason
())
.
isEqualTo
(
Reason
.
SERVICE_UNAVAILABLE
))
.
isEqualTo
(
Reason
.
SERVICE_UNAVAILABLE
))
.
verify
();
.
verify
();
}
}
...
@@ -110,51 +108,49 @@ public class ReactiveCloudFoundrySecurityInterceptorTests {
...
@@ -110,51 +108,49 @@ public class ReactiveCloudFoundrySecurityInterceptorTests {
@Test
@Test
public
void
preHandleWhenCloudFoundrySecurityServiceIsNullShouldReturnError
()
public
void
preHandleWhenCloudFoundrySecurityServiceIsNullShouldReturnError
()
throws
Exception
{
throws
Exception
{
this
.
interceptor
=
new
ReactiveCloudFoundrySecurityInterceptor
(
this
.
tokenValidator
,
null
,
this
.
interceptor
=
new
ReactiveCloudFoundrySecurityInterceptor
(
"my-app-id"
);
this
.
tokenValidator
,
null
,
"my-app-id"
);
MockServerWebExchange
request
=
MockServerWebExchange
MockServerWebExchange
request
=
MockServerWebExchange
.
from
(
MockServerHttpRequest
.
from
(
MockServerHttpRequest
.
get
(
"/a"
)
.
get
(
"/a"
).
header
(
HttpHeaders
.
AUTHORIZATION
,
mockAccessToken
()).
build
());
.
header
(
HttpHeaders
.
AUTHORIZATION
,
mockAccessToken
())
.
build
());
StepVerifier
.
create
(
this
.
interceptor
.
preHandle
(
request
,
"/a"
))
StepVerifier
.
create
(
this
.
interceptor
.
preHandle
(
request
,
"/a"
))
.
consumeErrorWith
(
throwable
->
assertThat
(((
CloudFoundryAuthorizationException
)
throwable
).
getReason
())
.
consumeErrorWith
((
ex
)
->
assertThat
(
((
CloudFoundryAuthorizationException
)
ex
).
getReason
())
.
isEqualTo
(
Reason
.
SERVICE_UNAVAILABLE
))
.
isEqualTo
(
Reason
.
SERVICE_UNAVAILABLE
))
.
verify
();
.
verify
();
}
}
@Test
@Test
public
void
preHandleWhenAccessIsNotAllowedShouldReturnAccessDenied
()
throws
Exception
{
public
void
preHandleWhenAccessIsNotAllowedShouldReturnAccessDenied
()
BDDMockito
.
given
(
this
.
securityService
.
getAccessLevel
(
mockAccessToken
(),
"my-app-id"
))
throws
Exception
{
given
(
this
.
securityService
.
getAccessLevel
(
mockAccessToken
(),
"my-app-id"
))
.
willReturn
(
Mono
.
just
(
AccessLevel
.
RESTRICTED
));
.
willReturn
(
Mono
.
just
(
AccessLevel
.
RESTRICTED
));
BDDMockito
.
given
(
this
.
tokenValidator
.
validate
(
any
()))
given
(
this
.
tokenValidator
.
validate
(
any
())).
willReturn
(
Mono
.
empty
());
.
willReturn
(
Mono
.
empty
());
MockServerWebExchange
request
=
MockServerWebExchange
MockServerWebExchange
request
=
MockServerWebExchange
.
from
(
MockServerHttpRequest
.
get
(
"/a"
)
.
from
(
MockServerHttpRequest
.
get
(
"/a"
)
.
header
(
HttpHeaders
.
AUTHORIZATION
,
"bearer "
+
mockAccessToken
())
.
header
(
HttpHeaders
.
AUTHORIZATION
,
"bearer "
+
mockAccessToken
())
.
build
());
.
build
());
StepVerifier
.
create
(
this
.
interceptor
.
preHandle
(
request
,
"/a"
))
StepVerifier
.
create
(
this
.
interceptor
.
preHandle
(
request
,
"/a"
))
.
consumeNextWith
(
response
->
{
.
consumeNextWith
(
(
response
)
->
{
assertThat
(
response
.
getStatus
())
assertThat
(
response
.
getStatus
())
.
isEqualTo
(
Reason
.
ACCESS_DENIED
.
getStatus
());
.
isEqualTo
(
Reason
.
ACCESS_DENIED
.
getStatus
());
})
}).
verifyComplete
();
.
verifyComplete
();
}
}
@Test
@Test
public
void
preHandleSuccessfulWithFullAccess
()
throws
Exception
{
public
void
preHandleSuccessfulWithFullAccess
()
throws
Exception
{
String
accessToken
=
mockAccessToken
();
String
accessToken
=
mockAccessToken
();
BDDMockito
.
given
(
this
.
securityService
.
getAccessLevel
(
accessToken
,
"my-app-id"
))
given
(
this
.
securityService
.
getAccessLevel
(
accessToken
,
"my-app-id"
))
.
willReturn
(
Mono
.
just
(
AccessLevel
.
FULL
));
.
willReturn
(
Mono
.
just
(
AccessLevel
.
FULL
));
BDDMockito
.
given
(
this
.
tokenValidator
.
validate
(
any
()))
given
(
this
.
tokenValidator
.
validate
(
any
())).
willReturn
(
Mono
.
empty
());
.
willReturn
(
Mono
.
empty
());
MockServerWebExchange
exchange
=
MockServerWebExchange
MockServerWebExchange
exchange
=
MockServerWebExchange
.
from
(
MockServerHttpRequest
.
get
(
"/a"
)
.
from
(
MockServerHttpRequest
.
get
(
"/a"
)
.
header
(
HttpHeaders
.
AUTHORIZATION
,
"bearer "
+
mockAccessToken
())
.
header
(
HttpHeaders
.
AUTHORIZATION
,
"bearer "
+
mockAccessToken
())
.
build
());
.
build
());
StepVerifier
.
create
(
this
.
interceptor
.
preHandle
(
exchange
,
"/a"
))
StepVerifier
.
create
(
this
.
interceptor
.
preHandle
(
exchange
,
"/a"
))
.
consumeNextWith
(
response
->
{
.
consumeNextWith
(
(
response
)
->
{
assertThat
(
response
.
getStatus
()).
isEqualTo
(
HttpStatus
.
OK
);
assertThat
(
response
.
getStatus
()).
isEqualTo
(
HttpStatus
.
OK
);
assertThat
((
AccessLevel
)
exchange
.
getAttribute
(
"cloudFoundryAccessLevel"
))
assertThat
((
AccessLevel
)
exchange
.
getAttribute
(
"cloudFoundryAccessLevel"
))
.
isEqualTo
(
AccessLevel
.
FULL
);
.
isEqualTo
(
AccessLevel
.
FULL
);
}).
verifyComplete
();
}).
verifyComplete
();
}
}
...
@@ -162,18 +158,18 @@ public class ReactiveCloudFoundrySecurityInterceptorTests {
...
@@ -162,18 +158,18 @@ public class ReactiveCloudFoundrySecurityInterceptorTests {
@Test
@Test
public
void
preHandleSuccessfulWithRestrictedAccess
()
throws
Exception
{
public
void
preHandleSuccessfulWithRestrictedAccess
()
throws
Exception
{
String
accessToken
=
mockAccessToken
();
String
accessToken
=
mockAccessToken
();
BDDMockito
.
given
(
this
.
securityService
.
getAccessLevel
(
accessToken
,
"my-app-id"
))
given
(
this
.
securityService
.
getAccessLevel
(
accessToken
,
"my-app-id"
))
.
willReturn
(
Mono
.
just
(
AccessLevel
.
RESTRICTED
));
.
willReturn
(
Mono
.
just
(
AccessLevel
.
RESTRICTED
));
BDDMockito
.
given
(
this
.
tokenValidator
.
validate
(
any
()))
given
(
this
.
tokenValidator
.
validate
(
any
())).
willReturn
(
Mono
.
empty
());
.
willReturn
(
Mono
.
empty
());
MockServerWebExchange
exchange
=
MockServerWebExchange
MockServerWebExchange
exchange
=
MockServerWebExchange
.
from
(
MockServerHttpRequest
.
get
(
"/info"
)
.
from
(
MockServerHttpRequest
.
get
(
"/info"
)
.
header
(
HttpHeaders
.
AUTHORIZATION
,
"bearer "
+
mockAccessToken
())
.
header
(
HttpHeaders
.
AUTHORIZATION
,
"bearer "
+
mockAccessToken
())
.
build
());
.
build
());
StepVerifier
.
create
(
this
.
interceptor
.
preHandle
(
exchange
,
"info"
))
StepVerifier
.
create
(
this
.
interceptor
.
preHandle
(
exchange
,
"info"
))
.
consumeNextWith
(
response
->
{
.
consumeNextWith
((
response
)
->
{
assertThat
(
response
.
getStatus
()).
isEqualTo
(
HttpStatus
.
OK
);
assertThat
(
response
.
getStatus
()).
isEqualTo
(
HttpStatus
.
OK
);
assertThat
((
AccessLevel
)
exchange
.
getAttribute
(
"cloudFoundryAccessLevel"
))
assertThat
((
AccessLevel
)
exchange
.
getAttribute
(
"cloudFoundryAccessLevel"
))
.
isEqualTo
(
AccessLevel
.
RESTRICTED
);
.
isEqualTo
(
AccessLevel
.
RESTRICTED
);
}).
verifyComplete
();
}).
verifyComplete
();
}
}
...
...
spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveCloudFoundrySecurityServiceTests.java
View file @
3f00ba3c
This diff is collapsed.
Click to expand it.
spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/reactive/ReactiveTokenValidatorTests.java
View file @
3f00ba3c
...
@@ -100,41 +100,50 @@ public class ReactiveTokenValidatorTests {
...
@@ -100,41 +100,50 @@ public class ReactiveTokenValidatorTests {
public
void
validateTokenWhenKidValidationFailsShouldThrowException
()
public
void
validateTokenWhenKidValidationFailsShouldThrowException
()
throws
Exception
{
throws
Exception
{
given
(
this
.
securityService
.
fetchTokenKeys
()).
willReturn
(
Mono
.
just
(
INVALID_KEYS
));
given
(
this
.
securityService
.
fetchTokenKeys
()).
willReturn
(
Mono
.
just
(
INVALID_KEYS
));
given
(
this
.
securityService
.
getUaaUrl
()).
willReturn
(
Mono
.
just
(
"http://localhost:8080/uaa"
));
given
(
this
.
securityService
.
getUaaUrl
())
.
willReturn
(
Mono
.
just
(
"http://localhost:8080/uaa"
));
String
header
=
"{\"alg\": \"RS256\", \"kid\": \"valid-key\",\"typ\": \"JWT\"}"
;
String
header
=
"{\"alg\": \"RS256\", \"kid\": \"valid-key\",\"typ\": \"JWT\"}"
;
String
claims
=
"{\"exp\": 2147483647, \"iss\": \"http://localhost:8080/uaa/oauth/token\", \"scope\": [\"actuator.read\"]}"
;
String
claims
=
"{\"exp\": 2147483647, \"iss\": \"http://localhost:8080/uaa/oauth/token\", \"scope\": [\"actuator.read\"]}"
;
StepVerifier
.
create
(
this
.
tokenValidator
.
validate
(
StepVerifier
new
Token
(
getSignedToken
(
header
.
getBytes
(),
claims
.
getBytes
())))).
consumeErrorWith
(
throwable
->
{
.
create
(
this
.
tokenValidator
.
validate
(
assertThat
(
throwable
).
isExactlyInstanceOf
(
CloudFoundryAuthorizationException
.
class
);
new
Token
(
getSignedToken
(
header
.
getBytes
(),
claims
.
getBytes
()))))
assertThat
(((
CloudFoundryAuthorizationException
)
throwable
)
.
consumeErrorWith
((
ex
)
->
{
.
getReason
()).
isEqualTo
(
Reason
.
INVALID_KEY_ID
);
assertThat
(
ex
).
isExactlyInstanceOf
(
CloudFoundryAuthorizationException
.
class
);
assertThat
(((
CloudFoundryAuthorizationException
)
ex
).
getReason
())
.
isEqualTo
(
Reason
.
INVALID_KEY_ID
);
}).
verify
();
}).
verify
();
}
}
@Test
@Test
public
void
validateTokenWhenKidValidationSucceeds
()
public
void
validateTokenWhenKidValidationSucceeds
()
throws
Exception
{
throws
Exception
{
given
(
this
.
securityService
.
fetchTokenKeys
()).
willReturn
(
Mono
.
just
(
VALID_KEYS
));
given
(
this
.
securityService
.
fetchTokenKeys
()).
willReturn
(
Mono
.
just
(
VALID_KEYS
));
given
(
this
.
securityService
.
getUaaUrl
()).
willReturn
(
Mono
.
just
(
"http://localhost:8080/uaa"
));
given
(
this
.
securityService
.
getUaaUrl
())
.
willReturn
(
Mono
.
just
(
"http://localhost:8080/uaa"
));
String
header
=
"{ \"alg\": \"RS256\", \"kid\": \"valid-key\",\"typ\": \"JWT\"}"
;
String
header
=
"{ \"alg\": \"RS256\", \"kid\": \"valid-key\",\"typ\": \"JWT\"}"
;
String
claims
=
"{ \"exp\": 2147483647, \"iss\": \"http://localhost:8080/uaa/oauth/token\", \"scope\": [\"actuator.read\"]}"
;
String
claims
=
"{ \"exp\": 2147483647, \"iss\": \"http://localhost:8080/uaa/oauth/token\", \"scope\": [\"actuator.read\"]}"
;
StepVerifier
.
create
(
this
.
tokenValidator
.
validate
(
StepVerifier
new
Token
(
getSignedToken
(
header
.
getBytes
(),
claims
.
getBytes
())))).
verifyComplete
();
.
create
(
this
.
tokenValidator
.
validate
(
new
Token
(
getSignedToken
(
header
.
getBytes
(),
claims
.
getBytes
()))))
.
verifyComplete
();
}
}
@Test
@Test
public
void
validateTokenWhenSignatureInvalidShouldThrowException
()
throws
Exception
{
public
void
validateTokenWhenSignatureInvalidShouldThrowException
()
throws
Exception
{
Map
<
String
,
String
>
KEYS
=
Collections
Map
<
String
,
String
>
KEYS
=
Collections
.
singletonMap
(
"valid-key"
,
INVALID_KEY
);
.
singletonMap
(
"valid-key"
,
INVALID_KEY
);
given
(
this
.
securityService
.
fetchTokenKeys
()).
willReturn
(
Mono
.
just
(
KEYS
));
given
(
this
.
securityService
.
fetchTokenKeys
()).
willReturn
(
Mono
.
just
(
KEYS
));
given
(
this
.
securityService
.
getUaaUrl
()).
willReturn
(
Mono
.
just
(
"http://localhost:8080/uaa"
));
given
(
this
.
securityService
.
getUaaUrl
())
.
willReturn
(
Mono
.
just
(
"http://localhost:8080/uaa"
));
String
header
=
"{ \"alg\": \"RS256\", \"kid\": \"valid-key\",\"typ\": \"JWT\"}"
;
String
header
=
"{ \"alg\": \"RS256\", \"kid\": \"valid-key\",\"typ\": \"JWT\"}"
;
String
claims
=
"{ \"exp\": 2147483647, \"iss\": \"http://localhost:8080/uaa/oauth/token\", \"scope\": [\"actuator.read\"]}"
;
String
claims
=
"{ \"exp\": 2147483647, \"iss\": \"http://localhost:8080/uaa/oauth/token\", \"scope\": [\"actuator.read\"]}"
;
StepVerifier
.
create
(
this
.
tokenValidator
.
validate
(
StepVerifier
new
Token
(
getSignedToken
(
header
.
getBytes
(),
claims
.
getBytes
())))).
consumeErrorWith
(
throwable
->
{
.
create
(
this
.
tokenValidator
.
validate
(
assertThat
(
throwable
).
isExactlyInstanceOf
(
CloudFoundryAuthorizationException
.
class
);
new
Token
(
getSignedToken
(
header
.
getBytes
(),
claims
.
getBytes
()))))
assertThat
(((
CloudFoundryAuthorizationException
)
throwable
)
.
consumeErrorWith
((
ex
)
->
{
.
getReason
()).
isEqualTo
(
Reason
.
INVALID_SIGNATURE
);
assertThat
(
ex
).
isExactlyInstanceOf
(
CloudFoundryAuthorizationException
.
class
);
assertThat
(((
CloudFoundryAuthorizationException
)
ex
).
getReason
())
.
isEqualTo
(
Reason
.
INVALID_SIGNATURE
);
}).
verify
();
}).
verify
();
}
}
...
@@ -142,42 +151,54 @@ public class ReactiveTokenValidatorTests {
...
@@ -142,42 +151,54 @@ public class ReactiveTokenValidatorTests {
public
void
validateTokenWhenTokenAlgorithmIsNotRS256ShouldThrowException
()
public
void
validateTokenWhenTokenAlgorithmIsNotRS256ShouldThrowException
()
throws
Exception
{
throws
Exception
{
given
(
this
.
securityService
.
fetchTokenKeys
()).
willReturn
(
Mono
.
just
(
VALID_KEYS
));
given
(
this
.
securityService
.
fetchTokenKeys
()).
willReturn
(
Mono
.
just
(
VALID_KEYS
));
given
(
this
.
securityService
.
getUaaUrl
()).
willReturn
(
Mono
.
just
(
"http://localhost:8080/uaa"
));
given
(
this
.
securityService
.
getUaaUrl
())
.
willReturn
(
Mono
.
just
(
"http://localhost:8080/uaa"
));
String
header
=
"{ \"alg\": \"HS256\", \"kid\": \"valid-key\", \"typ\": \"JWT\"}"
;
String
header
=
"{ \"alg\": \"HS256\", \"kid\": \"valid-key\", \"typ\": \"JWT\"}"
;
String
claims
=
"{ \"exp\": 2147483647, \"iss\": \"http://localhost:8080/uaa/oauth/token\", \"scope\": [\"actuator.read\"]}"
;
String
claims
=
"{ \"exp\": 2147483647, \"iss\": \"http://localhost:8080/uaa/oauth/token\", \"scope\": [\"actuator.read\"]}"
;
StepVerifier
.
create
(
this
.
tokenValidator
.
validate
(
StepVerifier
new
Token
(
getSignedToken
(
header
.
getBytes
(),
claims
.
getBytes
())))).
consumeErrorWith
(
throwable
->
{
.
create
(
this
.
tokenValidator
.
validate
(
assertThat
(
throwable
).
isExactlyInstanceOf
(
CloudFoundryAuthorizationException
.
class
);
new
Token
(
getSignedToken
(
header
.
getBytes
(),
claims
.
getBytes
()))))
assertThat
(((
CloudFoundryAuthorizationException
)
throwable
)
.
consumeErrorWith
((
ex
)
->
{
.
getReason
()).
isEqualTo
(
Reason
.
UNSUPPORTED_TOKEN_SIGNING_ALGORITHM
);
assertThat
(
ex
).
isExactlyInstanceOf
(
CloudFoundryAuthorizationException
.
class
);
assertThat
(((
CloudFoundryAuthorizationException
)
ex
).
getReason
())
.
isEqualTo
(
Reason
.
UNSUPPORTED_TOKEN_SIGNING_ALGORITHM
);
}).
verify
();
}).
verify
();
}
}
@Test
@Test
public
void
validateTokenWhenExpiredShouldThrowException
()
throws
Exception
{
public
void
validateTokenWhenExpiredShouldThrowException
()
throws
Exception
{
given
(
this
.
securityService
.
fetchTokenKeys
()).
willReturn
(
Mono
.
just
(
VALID_KEYS
));
given
(
this
.
securityService
.
fetchTokenKeys
()).
willReturn
(
Mono
.
just
(
VALID_KEYS
));
given
(
this
.
securityService
.
getUaaUrl
()).
willReturn
(
Mono
.
just
(
"http://localhost:8080/uaa"
));
given
(
this
.
securityService
.
getUaaUrl
())
.
willReturn
(
Mono
.
just
(
"http://localhost:8080/uaa"
));
String
header
=
"{ \"alg\": \"RS256\", \"kid\": \"valid-key\", \"typ\": \"JWT\"}"
;
String
header
=
"{ \"alg\": \"RS256\", \"kid\": \"valid-key\", \"typ\": \"JWT\"}"
;
String
claims
=
"{ \"jti\": \"0236399c350c47f3ae77e67a75e75e7d\", \"exp\": 1477509977, \"scope\": [\"actuator.read\"]}"
;
String
claims
=
"{ \"jti\": \"0236399c350c47f3ae77e67a75e75e7d\", \"exp\": 1477509977, \"scope\": [\"actuator.read\"]}"
;
StepVerifier
.
create
(
this
.
tokenValidator
.
validate
(
StepVerifier
new
Token
(
getSignedToken
(
header
.
getBytes
(),
claims
.
getBytes
())))).
consumeErrorWith
(
throwable
->
{
.
create
(
this
.
tokenValidator
.
validate
(
assertThat
(
throwable
).
isExactlyInstanceOf
(
CloudFoundryAuthorizationException
.
class
);
new
Token
(
getSignedToken
(
header
.
getBytes
(),
claims
.
getBytes
()))))
assertThat
(((
CloudFoundryAuthorizationException
)
throwable
)
.
consumeErrorWith
((
ex
)
->
{
.
getReason
()).
isEqualTo
(
Reason
.
TOKEN_EXPIRED
);
assertThat
(
ex
).
isExactlyInstanceOf
(
CloudFoundryAuthorizationException
.
class
);
assertThat
(((
CloudFoundryAuthorizationException
)
ex
).
getReason
())
.
isEqualTo
(
Reason
.
TOKEN_EXPIRED
);
}).
verify
();
}).
verify
();
}
}
@Test
@Test
public
void
validateTokenWhenIssuerIsNotValidShouldThrowException
()
throws
Exception
{
public
void
validateTokenWhenIssuerIsNotValidShouldThrowException
()
throws
Exception
{
given
(
this
.
securityService
.
fetchTokenKeys
()).
willReturn
(
Mono
.
just
(
VALID_KEYS
));
given
(
this
.
securityService
.
fetchTokenKeys
()).
willReturn
(
Mono
.
just
(
VALID_KEYS
));
given
(
this
.
securityService
.
getUaaUrl
()).
willReturn
(
Mono
.
just
(
"http://other-uaa.com"
));
given
(
this
.
securityService
.
getUaaUrl
())
.
willReturn
(
Mono
.
just
(
"http://other-uaa.com"
));
String
header
=
"{ \"alg\": \"RS256\", \"kid\": \"valid-key\", \"typ\": \"JWT\", \"scope\": [\"actuator.read\"]}"
;
String
header
=
"{ \"alg\": \"RS256\", \"kid\": \"valid-key\", \"typ\": \"JWT\", \"scope\": [\"actuator.read\"]}"
;
String
claims
=
"{ \"exp\": 2147483647, \"iss\": \"http://localhost:8080/uaa/oauth/token\", \"scope\": [\"foo.bar\"]}"
;
String
claims
=
"{ \"exp\": 2147483647, \"iss\": \"http://localhost:8080/uaa/oauth/token\", \"scope\": [\"foo.bar\"]}"
;
StepVerifier
.
create
(
this
.
tokenValidator
.
validate
(
StepVerifier
new
Token
(
getSignedToken
(
header
.
getBytes
(),
claims
.
getBytes
())))).
consumeErrorWith
(
throwable
->
{
.
create
(
this
.
tokenValidator
.
validate
(
assertThat
(
throwable
).
isExactlyInstanceOf
(
CloudFoundryAuthorizationException
.
class
);
new
Token
(
getSignedToken
(
header
.
getBytes
(),
claims
.
getBytes
()))))
assertThat
(((
CloudFoundryAuthorizationException
)
throwable
)
.
consumeErrorWith
((
ex
)
->
{
.
getReason
()).
isEqualTo
(
Reason
.
INVALID_ISSUER
);
assertThat
(
ex
).
isExactlyInstanceOf
(
CloudFoundryAuthorizationException
.
class
);
assertThat
(((
CloudFoundryAuthorizationException
)
ex
).
getReason
())
.
isEqualTo
(
Reason
.
INVALID_ISSUER
);
}).
verify
();
}).
verify
();
}
}
...
@@ -185,14 +206,18 @@ public class ReactiveTokenValidatorTests {
...
@@ -185,14 +206,18 @@ public class ReactiveTokenValidatorTests {
public
void
validateTokenWhenAudienceIsNotValidShouldThrowException
()
public
void
validateTokenWhenAudienceIsNotValidShouldThrowException
()
throws
Exception
{
throws
Exception
{
given
(
this
.
securityService
.
fetchTokenKeys
()).
willReturn
(
Mono
.
just
(
VALID_KEYS
));
given
(
this
.
securityService
.
fetchTokenKeys
()).
willReturn
(
Mono
.
just
(
VALID_KEYS
));
given
(
this
.
securityService
.
getUaaUrl
()).
willReturn
(
Mono
.
just
(
"http://localhost:8080/uaa"
));
given
(
this
.
securityService
.
getUaaUrl
())
.
willReturn
(
Mono
.
just
(
"http://localhost:8080/uaa"
));
String
header
=
"{ \"alg\": \"RS256\", \"kid\": \"valid-key\", \"typ\": \"JWT\"}"
;
String
header
=
"{ \"alg\": \"RS256\", \"kid\": \"valid-key\", \"typ\": \"JWT\"}"
;
String
claims
=
"{ \"exp\": 2147483647, \"iss\": \"http://localhost:8080/uaa/oauth/token\", \"scope\": [\"foo.bar\"]}"
;
String
claims
=
"{ \"exp\": 2147483647, \"iss\": \"http://localhost:8080/uaa/oauth/token\", \"scope\": [\"foo.bar\"]}"
;
StepVerifier
.
create
(
this
.
tokenValidator
.
validate
(
StepVerifier
new
Token
(
getSignedToken
(
header
.
getBytes
(),
claims
.
getBytes
())))).
consumeErrorWith
(
throwable
->
{
.
create
(
this
.
tokenValidator
.
validate
(
assertThat
(
throwable
).
isExactlyInstanceOf
(
CloudFoundryAuthorizationException
.
class
);
new
Token
(
getSignedToken
(
header
.
getBytes
(),
claims
.
getBytes
()))))
assertThat
(((
CloudFoundryAuthorizationException
)
throwable
)
.
consumeErrorWith
((
ex
)
->
{
.
getReason
()).
isEqualTo
(
Reason
.
INVALID_AUDIENCE
);
assertThat
(
ex
).
isExactlyInstanceOf
(
CloudFoundryAuthorizationException
.
class
);
assertThat
(((
CloudFoundryAuthorizationException
)
ex
).
getReason
())
.
isEqualTo
(
Reason
.
INVALID_AUDIENCE
);
}).
verify
();
}).
verify
();
}
}
...
...
spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/cloudfoundry/servlet/CloudFoundrySecurityInterceptorTests.java
View file @
3f00ba3c
...
@@ -65,15 +65,13 @@ public class CloudFoundrySecurityInterceptorTests {
...
@@ -65,15 +65,13 @@ public class CloudFoundrySecurityInterceptorTests {
this
.
request
.
setMethod
(
"OPTIONS"
);
this
.
request
.
setMethod
(
"OPTIONS"
);
this
.
request
.
addHeader
(
HttpHeaders
.
ORIGIN
,
"http://example.com"
);
this
.
request
.
addHeader
(
HttpHeaders
.
ORIGIN
,
"http://example.com"
);
this
.
request
.
addHeader
(
HttpHeaders
.
ACCESS_CONTROL_REQUEST_METHOD
,
"GET"
);
this
.
request
.
addHeader
(
HttpHeaders
.
ACCESS_CONTROL_REQUEST_METHOD
,
"GET"
);
SecurityResponse
response
=
this
.
interceptor
SecurityResponse
response
=
this
.
interceptor
.
preHandle
(
this
.
request
,
"/a"
);
.
preHandle
(
this
.
request
,
"/a"
);
assertThat
(
response
.
getStatus
()).
isEqualTo
(
HttpStatus
.
OK
);
assertThat
(
response
.
getStatus
()).
isEqualTo
(
HttpStatus
.
OK
);
}
}
@Test
@Test
public
void
preHandleWhenTokenIsMissingShouldReturnFalse
()
throws
Exception
{
public
void
preHandleWhenTokenIsMissingShouldReturnFalse
()
throws
Exception
{
SecurityResponse
response
=
this
.
interceptor
SecurityResponse
response
=
this
.
interceptor
.
preHandle
(
this
.
request
,
"/a"
);
.
preHandle
(
this
.
request
,
"/a"
);
assertThat
(
response
.
getStatus
())
assertThat
(
response
.
getStatus
())
.
isEqualTo
(
Reason
.
MISSING_AUTHORIZATION
.
getStatus
());
.
isEqualTo
(
Reason
.
MISSING_AUTHORIZATION
.
getStatus
());
}
}
...
@@ -81,8 +79,7 @@ public class CloudFoundrySecurityInterceptorTests {
...
@@ -81,8 +79,7 @@ public class CloudFoundrySecurityInterceptorTests {
@Test
@Test
public
void
preHandleWhenTokenIsNotBearerShouldReturnFalse
()
throws
Exception
{
public
void
preHandleWhenTokenIsNotBearerShouldReturnFalse
()
throws
Exception
{
this
.
request
.
addHeader
(
"Authorization"
,
mockAccessToken
());
this
.
request
.
addHeader
(
"Authorization"
,
mockAccessToken
());
SecurityResponse
response
=
this
.
interceptor
SecurityResponse
response
=
this
.
interceptor
.
preHandle
(
this
.
request
,
"/a"
);
.
preHandle
(
this
.
request
,
"/a"
);
assertThat
(
response
.
getStatus
())
assertThat
(
response
.
getStatus
())
.
isEqualTo
(
Reason
.
MISSING_AUTHORIZATION
.
getStatus
());
.
isEqualTo
(
Reason
.
MISSING_AUTHORIZATION
.
getStatus
());
}
}
...
@@ -92,8 +89,7 @@ public class CloudFoundrySecurityInterceptorTests {
...
@@ -92,8 +89,7 @@ public class CloudFoundrySecurityInterceptorTests {
this
.
interceptor
=
new
CloudFoundrySecurityInterceptor
(
this
.
tokenValidator
,
this
.
interceptor
=
new
CloudFoundrySecurityInterceptor
(
this
.
tokenValidator
,
this
.
securityService
,
null
);
this
.
securityService
,
null
);
this
.
request
.
addHeader
(
"Authorization"
,
"bearer "
+
mockAccessToken
());
this
.
request
.
addHeader
(
"Authorization"
,
"bearer "
+
mockAccessToken
());
SecurityResponse
response
=
this
.
interceptor
SecurityResponse
response
=
this
.
interceptor
.
preHandle
(
this
.
request
,
"/a"
);
.
preHandle
(
this
.
request
,
"/a"
);
assertThat
(
response
.
getStatus
())
assertThat
(
response
.
getStatus
())
.
isEqualTo
(
Reason
.
SERVICE_UNAVAILABLE
.
getStatus
());
.
isEqualTo
(
Reason
.
SERVICE_UNAVAILABLE
.
getStatus
());
}
}
...
@@ -104,8 +100,7 @@ public class CloudFoundrySecurityInterceptorTests {
...
@@ -104,8 +100,7 @@ public class CloudFoundrySecurityInterceptorTests {
this
.
interceptor
=
new
CloudFoundrySecurityInterceptor
(
this
.
tokenValidator
,
null
,
this
.
interceptor
=
new
CloudFoundrySecurityInterceptor
(
this
.
tokenValidator
,
null
,
"my-app-id"
);
"my-app-id"
);
this
.
request
.
addHeader
(
"Authorization"
,
"bearer "
+
mockAccessToken
());
this
.
request
.
addHeader
(
"Authorization"
,
"bearer "
+
mockAccessToken
());
SecurityResponse
response
=
this
.
interceptor
SecurityResponse
response
=
this
.
interceptor
.
preHandle
(
this
.
request
,
"/a"
);
.
preHandle
(
this
.
request
,
"/a"
);
assertThat
(
response
.
getStatus
())
assertThat
(
response
.
getStatus
())
.
isEqualTo
(
Reason
.
SERVICE_UNAVAILABLE
.
getStatus
());
.
isEqualTo
(
Reason
.
SERVICE_UNAVAILABLE
.
getStatus
());
}
}
...
@@ -116,8 +111,7 @@ public class CloudFoundrySecurityInterceptorTests {
...
@@ -116,8 +111,7 @@ public class CloudFoundrySecurityInterceptorTests {
this
.
request
.
addHeader
(
"Authorization"
,
"bearer "
+
accessToken
);
this
.
request
.
addHeader
(
"Authorization"
,
"bearer "
+
accessToken
);
given
(
this
.
securityService
.
getAccessLevel
(
accessToken
,
"my-app-id"
))
given
(
this
.
securityService
.
getAccessLevel
(
accessToken
,
"my-app-id"
))
.
willReturn
(
AccessLevel
.
RESTRICTED
);
.
willReturn
(
AccessLevel
.
RESTRICTED
);
SecurityResponse
response
=
this
.
interceptor
SecurityResponse
response
=
this
.
interceptor
.
preHandle
(
this
.
request
,
"/a"
);
.
preHandle
(
this
.
request
,
"/a"
);
assertThat
(
response
.
getStatus
()).
isEqualTo
(
Reason
.
ACCESS_DENIED
.
getStatus
());
assertThat
(
response
.
getStatus
()).
isEqualTo
(
Reason
.
ACCESS_DENIED
.
getStatus
());
}
}
...
@@ -127,8 +121,7 @@ public class CloudFoundrySecurityInterceptorTests {
...
@@ -127,8 +121,7 @@ public class CloudFoundrySecurityInterceptorTests {
this
.
request
.
addHeader
(
"Authorization"
,
"Bearer "
+
accessToken
);
this
.
request
.
addHeader
(
"Authorization"
,
"Bearer "
+
accessToken
);
given
(
this
.
securityService
.
getAccessLevel
(
accessToken
,
"my-app-id"
))
given
(
this
.
securityService
.
getAccessLevel
(
accessToken
,
"my-app-id"
))
.
willReturn
(
AccessLevel
.
FULL
);
.
willReturn
(
AccessLevel
.
FULL
);
SecurityResponse
response
=
this
.
interceptor
SecurityResponse
response
=
this
.
interceptor
.
preHandle
(
this
.
request
,
"/a"
);
.
preHandle
(
this
.
request
,
"/a"
);
ArgumentCaptor
<
Token
>
tokenArgumentCaptor
=
ArgumentCaptor
.
forClass
(
Token
.
class
);
ArgumentCaptor
<
Token
>
tokenArgumentCaptor
=
ArgumentCaptor
.
forClass
(
Token
.
class
);
verify
(
this
.
tokenValidator
).
validate
(
tokenArgumentCaptor
.
capture
());
verify
(
this
.
tokenValidator
).
validate
(
tokenArgumentCaptor
.
capture
());
Token
token
=
tokenArgumentCaptor
.
getValue
();
Token
token
=
tokenArgumentCaptor
.
getValue
();
...
@@ -144,8 +137,7 @@ public class CloudFoundrySecurityInterceptorTests {
...
@@ -144,8 +137,7 @@ public class CloudFoundrySecurityInterceptorTests {
this
.
request
.
addHeader
(
"Authorization"
,
"Bearer "
+
accessToken
);
this
.
request
.
addHeader
(
"Authorization"
,
"Bearer "
+
accessToken
);
given
(
this
.
securityService
.
getAccessLevel
(
accessToken
,
"my-app-id"
))
given
(
this
.
securityService
.
getAccessLevel
(
accessToken
,
"my-app-id"
))
.
willReturn
(
AccessLevel
.
RESTRICTED
);
.
willReturn
(
AccessLevel
.
RESTRICTED
);
SecurityResponse
response
=
this
.
interceptor
SecurityResponse
response
=
this
.
interceptor
.
preHandle
(
this
.
request
,
"info"
);
.
preHandle
(
this
.
request
,
"info"
);
ArgumentCaptor
<
Token
>
tokenArgumentCaptor
=
ArgumentCaptor
.
forClass
(
Token
.
class
);
ArgumentCaptor
<
Token
>
tokenArgumentCaptor
=
ArgumentCaptor
.
forClass
(
Token
.
class
);
verify
(
this
.
tokenValidator
).
validate
(
tokenArgumentCaptor
.
capture
());
verify
(
this
.
tokenValidator
).
validate
(
tokenArgumentCaptor
.
capture
());
Token
token
=
tokenArgumentCaptor
.
getValue
();
Token
token
=
tokenArgumentCaptor
.
getValue
();
...
...
spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/reactive/AbstractWebFluxEndpointHandlerMapping.java
View file @
3f00ba3c
...
@@ -48,8 +48,10 @@ import org.springframework.web.util.pattern.PathPatternParser;
...
@@ -48,8 +48,10 @@ import org.springframework.web.util.pattern.PathPatternParser;
*
*
* @author Andy Wilkinson
* @author Andy Wilkinson
* @author Madhura Bhave
* @author Madhura Bhave
* @since 2.0.0
*/
*/
public
abstract
class
AbstractWebFluxEndpointHandlerMapping
extends
RequestMappingInfoHandlerMapping
{
public
abstract
class
AbstractWebFluxEndpointHandlerMapping
extends
RequestMappingInfoHandlerMapping
{
private
static
final
PathPatternParser
pathPatternParser
=
new
PathPatternParser
();
private
static
final
PathPatternParser
pathPatternParser
=
new
PathPatternParser
();
...
@@ -103,18 +105,16 @@ public abstract class AbstractWebFluxEndpointHandlerMapping extends RequestMappi
...
@@ -103,18 +105,16 @@ public abstract class AbstractWebFluxEndpointHandlerMapping extends RequestMappi
}
}
private
void
registerLinksMapping
()
{
private
void
registerLinksMapping
()
{
registerMapping
(
PatternsRequestCondition
patterns
=
new
PatternsRequestCondition
(
new
RequestMappingInfo
(
pathPatternParser
.
parse
(
this
.
endpointMapping
.
getPath
()));
new
PatternsRequestCondition
(
RequestMethodsRequestCondition
methods
=
new
RequestMethodsRequestCondition
(
pathPatternParser
.
parse
(
this
.
endpointMapping
.
getPath
())),
RequestMethod
.
GET
);
new
RequestMethodsRequestCondition
(
RequestMethod
.
GET
),
null
,
null
,
ProducesRequestCondition
produces
=
new
ProducesRequestCondition
(
null
,
this
.
endpointMediaTypes
.
getProduced
().
toArray
(
new
ProducesRequestCondition
(
new
String
[
this
.
endpointMediaTypes
.
getProduced
().
size
()]));
this
.
endpointMediaTypes
.
getProduced
()
RequestMappingInfo
mapping
=
new
RequestMappingInfo
(
patterns
,
methods
,
null
,
null
,
.
toArray
(
new
String
[
this
.
endpointMediaTypes
null
,
produces
,
null
);
.
getProduced
().
size
()])),
registerMapping
(
mapping
,
this
,
getLinks
());
null
),
this
,
getLinks
());
}
}
protected
RequestMappingInfo
createRequestMappingInfo
(
protected
RequestMappingInfo
createRequestMappingInfo
(
...
@@ -193,4 +193,3 @@ public abstract class AbstractWebFluxEndpointHandlerMapping extends RequestMappi
...
@@ -193,4 +193,3 @@ public abstract class AbstractWebFluxEndpointHandlerMapping extends RequestMappi
}
}
}
}
spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/web/reactive/WebFluxEndpointHandlerMapping.java
View file @
3f00ba3c
...
@@ -56,7 +56,8 @@ import org.springframework.web.util.UriComponentsBuilder;
...
@@ -56,7 +56,8 @@ import org.springframework.web.util.UriComponentsBuilder;
* @author Andy Wilkinson
* @author Andy Wilkinson
* @since 2.0.0
* @since 2.0.0
*/
*/
public
class
WebFluxEndpointHandlerMapping
extends
AbstractWebFluxEndpointHandlerMapping
implements
InitializingBean
{
public
class
WebFluxEndpointHandlerMapping
extends
AbstractWebFluxEndpointHandlerMapping
implements
InitializingBean
{
private
final
Method
handleRead
=
ReflectionUtils
private
final
Method
handleRead
=
ReflectionUtils
.
findMethod
(
ReadOperationHandler
.
class
,
"handle"
,
ServerWebExchange
.
class
);
.
findMethod
(
ReadOperationHandler
.
class
,
"handle"
,
ServerWebExchange
.
class
);
...
@@ -111,8 +112,10 @@ public class WebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointHandle
...
@@ -111,8 +112,10 @@ public class WebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointHandle
}
}
registerMapping
(
createRequestMappingInfo
(
operation
),
registerMapping
(
createRequestMappingInfo
(
operation
),
operationType
==
OperationType
.
WRITE
operationType
==
OperationType
.
WRITE
?
new
WebFluxEndpointHandlerMapping
.
WriteOperationHandler
(
operationInvoker
)
?
new
WebFluxEndpointHandlerMapping
.
WriteOperationHandler
(
:
new
WebFluxEndpointHandlerMapping
.
ReadOperationHandler
(
operationInvoker
),
operationInvoker
)
:
new
WebFluxEndpointHandlerMapping
.
ReadOperationHandler
(
operationInvoker
),
operationType
==
OperationType
.
WRITE
?
this
.
handleWrite
operationType
==
OperationType
.
WRITE
?
this
.
handleWrite
:
this
.
handleRead
);
:
this
.
handleRead
);
}
}
...
@@ -124,6 +127,7 @@ public class WebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointHandle
...
@@ -124,6 +127,7 @@ public class WebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointHandle
UriComponentsBuilder
.
fromUri
(
request
.
getURI
()).
replaceQuery
(
null
)
UriComponentsBuilder
.
fromUri
(
request
.
getURI
()).
replaceQuery
(
null
)
.
toUriString
()));
.
toUriString
()));
}
}
/**
/**
* Base class for handlers for endpoint operations.
* Base class for handlers for endpoint operations.
*/
*/
...
...
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