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
e57aafd6
Commit
e57aafd6
authored
Jan 09, 2018
by
Madhura Bhave
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Provide EndpointRequest for WebFlux-based Security
Closes gh-11022
parent
32557e49
Changes
14
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
785 additions
and
30 deletions
+785
-30
EndpointRequest.java
...uate/autoconfigure/security/reactive/EndpointRequest.java
+182
-0
EndpointRequest.java
...tuate/autoconfigure/security/servlet/EndpointRequest.java
+2
-13
EndpointRequestTests.java
...autoconfigure/security/reactive/EndpointRequestTests.java
+190
-0
EndpointRequestTests.java
.../autoconfigure/security/servlet/EndpointRequestTests.java
+1
-1
StaticResourceRequest.java
...rk/boot/autoconfigure/security/StaticResourceRequest.java
+1
-1
spring-boot-features.adoc
...ing-boot-docs/src/main/asciidoc/spring-boot-features.adoc
+26
-9
ApplicationContextServerWebExchangeMatcher.java
.../reactive/ApplicationContextServerWebExchangeMatcher.java
+104
-0
ApplicationContextRequestMatcher.java
...ot/security/servlet/ApplicationContextRequestMatcher.java
+2
-2
ApplicationContextServerWebExchangeMatcherTests.java
...tive/ApplicationContextServerWebExchangeMatcherTests.java
+157
-0
ApplicationContextRequestMatcherTests.java
...curity/servlet/ApplicationContextRequestMatcherTests.java
+1
-1
SecurityConfiguration.java
...sample/actuator/customsecurity/SecurityConfiguration.java
+1
-1
application.properties
...-secure-webflux/src/main/resources/application.properties
+2
-1
SampleSecureWebFluxCustomSecurityTests.java
...ecure/webflux/SampleSecureWebFluxCustomSecurityTests.java
+115
-0
SampleMethodSecurityApplication.java
...mple/security/method/SampleMethodSecurityApplication.java
+1
-1
No files found.
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequest.java
0 → 100644
View file @
e57aafd6
/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
actuate
.
autoconfigure
.
security
.
reactive
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
import
java.util.Collections
;
import
java.util.LinkedHashSet
;
import
java.util.List
;
import
java.util.Objects
;
import
java.util.Set
;
import
java.util.stream.Collectors
;
import
java.util.stream.Stream
;
import
reactor.core.publisher.Mono
;
import
org.springframework.boot.actuate.autoconfigure.endpoint.web.EndpointPathProvider
;
import
org.springframework.boot.actuate.endpoint.annotation.Endpoint
;
import
org.springframework.boot.security.reactive.ApplicationContextServerWebExchangeMatcher
;
import
org.springframework.core.annotation.AnnotationUtils
;
import
org.springframework.security.web.server.util.matcher.OrServerWebExchangeMatcher
;
import
org.springframework.security.web.server.util.matcher.PathPatternParserServerWebExchangeMatcher
;
import
org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher
;
import
org.springframework.util.Assert
;
import
org.springframework.web.server.ServerWebExchange
;
/**
* Factory that can be used to create a {@link ServerWebExchangeMatcher} for actuator endpoint
* locations.
*
* @author Madhura Bhave
* @since 2.0.0
*/
public
final
class
EndpointRequest
{
private
EndpointRequest
()
{
}
/**
* Returns a matcher that includes all {@link Endpoint actuator endpoints}. The
* {@link EndpointServerWebExchangeMatcher#excluding(Class...) excluding} method can be used to
* further remove specific endpoints if required. For example: <pre class="code">
* EndpointServerWebExchangeMatcher.toAnyEndpoint().excluding(ShutdownEndpoint.class)
* </pre>
* @return the configured {@link ServerWebExchangeMatcher}
*/
public
static
EndpointServerWebExchangeMatcher
toAnyEndpoint
()
{
return
new
EndpointServerWebExchangeMatcher
();
}
/**
* Returns a matcher that includes the specified {@link Endpoint actuator endpoints}.
* For example: <pre class="code">
* EndpointRequest.to(ShutdownEndpoint.class, HealthEndpoint.class)
* </pre>
* @param endpoints the endpoints to include
* @return the configured {@link ServerWebExchangeMatcher}
*/
public
static
EndpointServerWebExchangeMatcher
to
(
Class
<?>...
endpoints
)
{
return
new
EndpointServerWebExchangeMatcher
(
endpoints
);
}
/**
* Returns a matcher that includes the specified {@link Endpoint actuator endpoints}.
* For example: <pre class="code">
* EndpointRequest.to("shutdown", "health")
* </pre>
* @param endpoints the endpoints to include
* @return the configured {@link ServerWebExchangeMatcher}
*/
public
static
EndpointServerWebExchangeMatcher
to
(
String
...
endpoints
)
{
return
new
EndpointServerWebExchangeMatcher
(
endpoints
);
}
/**
* The {@link ServerWebExchangeMatcher} used to match against {@link Endpoint actuator endpoints}.
*/
public
final
static
class
EndpointServerWebExchangeMatcher
extends
ApplicationContextServerWebExchangeMatcher
<
EndpointPathProvider
>
{
private
final
List
<
Object
>
includes
;
private
final
List
<
Object
>
excludes
;
private
ServerWebExchangeMatcher
delegate
;
private
EndpointServerWebExchangeMatcher
()
{
super
(
EndpointPathProvider
.
class
);
this
.
includes
=
Collections
.
emptyList
();
this
.
excludes
=
Collections
.
emptyList
();
}
private
EndpointServerWebExchangeMatcher
(
Class
<?>[]
endpoints
)
{
super
(
EndpointPathProvider
.
class
);
this
.
includes
=
Arrays
.
asList
((
Object
[])
endpoints
);
this
.
excludes
=
Collections
.
emptyList
();
}
private
EndpointServerWebExchangeMatcher
(
String
[]
endpoints
)
{
super
(
EndpointPathProvider
.
class
);
this
.
includes
=
Arrays
.
asList
((
Object
[])
endpoints
);
this
.
excludes
=
Collections
.
emptyList
();
}
private
EndpointServerWebExchangeMatcher
(
List
<
Object
>
includes
,
List
<
Object
>
excludes
)
{
super
(
EndpointPathProvider
.
class
);
this
.
includes
=
includes
;
this
.
excludes
=
excludes
;
}
EndpointServerWebExchangeMatcher
excluding
(
Class
<?>...
endpoints
)
{
List
<
Object
>
excludes
=
new
ArrayList
<>(
this
.
excludes
);
excludes
.
addAll
(
Arrays
.
asList
((
Object
[])
endpoints
));
return
new
EndpointServerWebExchangeMatcher
(
this
.
includes
,
excludes
);
}
EndpointServerWebExchangeMatcher
excluding
(
String
...
endpoints
)
{
List
<
Object
>
excludes
=
new
ArrayList
<>(
this
.
excludes
);
excludes
.
addAll
(
Arrays
.
asList
((
Object
[])
endpoints
));
return
new
EndpointServerWebExchangeMatcher
(
this
.
includes
,
excludes
);
}
@Override
protected
void
initialized
(
EndpointPathProvider
endpointPathProvider
)
{
Set
<
String
>
paths
=
new
LinkedHashSet
<>(
this
.
includes
.
isEmpty
()
?
endpointPathProvider
.
getPaths
()
:
Collections
.
emptyList
());
streamPaths
(
this
.
includes
,
endpointPathProvider
).
forEach
(
paths:
:
add
);
streamPaths
(
this
.
excludes
,
endpointPathProvider
).
forEach
(
paths:
:
remove
);
this
.
delegate
=
new
OrServerWebExchangeMatcher
(
getDelegateMatchers
(
paths
));
}
private
Stream
<
String
>
streamPaths
(
List
<
Object
>
source
,
EndpointPathProvider
endpointPathProvider
)
{
return
source
.
stream
().
filter
(
Objects:
:
nonNull
).
map
(
this
::
getPathId
)
.
map
(
endpointPathProvider:
:
getPath
);
}
private
String
getPathId
(
Object
source
)
{
if
(
source
instanceof
String
)
{
return
(
String
)
source
;
}
if
(
source
instanceof
Class
)
{
return
getPathId
((
Class
<?>)
source
);
}
throw
new
IllegalStateException
(
"Unsupported source "
+
source
);
}
private
String
getPathId
(
Class
<?>
source
)
{
Endpoint
annotation
=
AnnotationUtils
.
findAnnotation
(
source
,
Endpoint
.
class
);
Assert
.
state
(
annotation
!=
null
,
()
->
"Class "
+
source
+
" is not annotated with @Endpoint"
);
return
annotation
.
id
();
}
private
List
<
ServerWebExchangeMatcher
>
getDelegateMatchers
(
Set
<
String
>
paths
)
{
return
paths
.
stream
().
map
((
path
)
->
new
PathPatternParserServerWebExchangeMatcher
(
path
+
"/**"
))
.
collect
(
Collectors
.
toList
());
}
@Override
protected
Mono
<
MatchResult
>
matches
(
ServerWebExchange
exchange
,
EndpointPathProvider
context
)
{
return
this
.
delegate
.
matches
(
exchange
);
}
}
}
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/EndpointRequest.java
→
spring-boot-project/spring-boot-actuator-autoconfigure/src/main/java/org/springframework/boot/actuate/autoconfigure/security/
servlet/
EndpointRequest.java
View file @
e57aafd6
...
...
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
actuate
.
autoconfigure
.
security
;
package
org
.
springframework
.
boot
.
actuate
.
autoconfigure
.
security
.
servlet
;
import
java.util.ArrayList
;
import
java.util.Arrays
;
...
...
@@ -28,10 +28,9 @@ import java.util.stream.Stream;
import
javax.servlet.http.HttpServletRequest
;
import
org.springframework.beans.factory.BeanCreationException
;
import
org.springframework.boot.actuate.autoconfigure.endpoint.web.EndpointPathProvider
;
import
org.springframework.boot.actuate.endpoint.annotation.Endpoint
;
import
org.springframework.boot.security.ApplicationContextRequestMatcher
;
import
org.springframework.boot.security.
servlet.
ApplicationContextRequestMatcher
;
import
org.springframework.core.annotation.AnnotationUtils
;
import
org.springframework.security.web.util.matcher.AntPathRequestMatcher
;
import
org.springframework.security.web.util.matcher.OrRequestMatcher
;
...
...
@@ -172,16 +171,6 @@ public final class EndpointRequest {
.
collect
(
Collectors
.
toList
());
}
@Override
public
boolean
matches
(
HttpServletRequest
request
)
{
try
{
return
super
.
matches
(
request
);
}
catch
(
BeanCreationException
ex
)
{
return
false
;
}
}
@Override
protected
boolean
matches
(
HttpServletRequest
request
,
EndpointPathProvider
context
)
{
...
...
spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/reactive/EndpointRequestTests.java
0 → 100644
View file @
e57aafd6
/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
actuate
.
autoconfigure
.
security
.
reactive
;
import
java.util.Arrays
;
import
java.util.List
;
import
org.assertj.core.api.AssertDelegateTarget
;
import
org.junit.Test
;
import
org.springframework.boot.actuate.autoconfigure.endpoint.web.EndpointPathProvider
;
import
org.springframework.boot.actuate.endpoint.annotation.Endpoint
;
import
org.springframework.context.support.StaticApplicationContext
;
import
org.springframework.http.server.reactive.ServerHttpRequest
;
import
org.springframework.http.server.reactive.ServerHttpResponse
;
import
org.springframework.mock.http.server.reactive.MockServerHttpRequest
;
import
org.springframework.mock.http.server.reactive.MockServerHttpResponse
;
import
org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher
;
import
org.springframework.web.server.ServerWebExchange
;
import
org.springframework.web.server.WebHandler
;
import
org.springframework.web.server.adapter.HttpWebHandlerAdapter
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
import
static
org
.
mockito
.
Mockito
.
mock
;
/**
* Tests for {@link EndpointRequest}.
*
* @author Madhura Bhave
*/
public
class
EndpointRequestTests
{
@Test
public
void
toAnyEndpointShouldMatchEndpointPath
()
{
ServerWebExchangeMatcher
matcher
=
EndpointRequest
.
toAnyEndpoint
();
assertMatcher
(
matcher
).
matches
(
"/actuator/foo"
);
assertMatcher
(
matcher
).
matches
(
"/actuator/bar"
);
}
@Test
public
void
toAnyEndpointShouldNotMatchOtherPath
()
{
ServerWebExchangeMatcher
matcher
=
EndpointRequest
.
toAnyEndpoint
();
assertMatcher
(
matcher
).
doesNotMatch
(
"/actuator/baz"
);
}
@Test
public
void
toEndpointClassShouldMatchEndpointPath
()
{
ServerWebExchangeMatcher
matcher
=
EndpointRequest
.
to
(
FooEndpoint
.
class
);
assertMatcher
(
matcher
).
matches
(
"/actuator/foo"
);
}
@Test
public
void
toEndpointClassShouldNotMatchOtherPath
()
{
ServerWebExchangeMatcher
matcher
=
EndpointRequest
.
to
(
FooEndpoint
.
class
);
assertMatcher
(
matcher
).
doesNotMatch
(
"/actuator/bar"
);
}
@Test
public
void
toEndpointIdShouldMatchEndpointPath
()
{
ServerWebExchangeMatcher
matcher
=
EndpointRequest
.
to
(
"foo"
);
assertMatcher
(
matcher
).
matches
(
"/actuator/foo"
);
}
@Test
public
void
toEndpointIdShouldNotMatchOtherPath
()
{
ServerWebExchangeMatcher
matcher
=
EndpointRequest
.
to
(
"foo"
);
assertMatcher
(
matcher
).
doesNotMatch
(
"/actuator/bar"
);
}
@Test
public
void
excludeByClassShouldNotMatchExcluded
()
{
ServerWebExchangeMatcher
matcher
=
EndpointRequest
.
toAnyEndpoint
()
.
excluding
(
FooEndpoint
.
class
);
assertMatcher
(
matcher
).
doesNotMatch
(
"/actuator/foo"
);
assertMatcher
(
matcher
).
matches
(
"/actuator/bar"
);
}
@Test
public
void
excludeByIdShouldNotMatchExcluded
()
{
ServerWebExchangeMatcher
matcher
=
EndpointRequest
.
toAnyEndpoint
().
excluding
(
"foo"
);
assertMatcher
(
matcher
).
doesNotMatch
(
"/actuator/foo"
);
assertMatcher
(
matcher
).
matches
(
"/actuator/bar"
);
}
private
RequestMatcherAssert
assertMatcher
(
ServerWebExchangeMatcher
matcher
)
{
return
assertMatcher
(
matcher
,
new
MockEndpointPathProvider
());
}
private
RequestMatcherAssert
assertMatcher
(
ServerWebExchangeMatcher
matcher
,
EndpointPathProvider
endpointPathProvider
)
{
StaticApplicationContext
context
=
new
StaticApplicationContext
();
context
.
registerBean
(
EndpointPathProvider
.
class
,
()
->
endpointPathProvider
);
return
assertThat
(
new
RequestMatcherAssert
(
context
,
matcher
));
}
private
static
class
RequestMatcherAssert
implements
AssertDelegateTarget
{
private
final
StaticApplicationContext
context
;
private
final
ServerWebExchangeMatcher
matcher
;
RequestMatcherAssert
(
StaticApplicationContext
context
,
ServerWebExchangeMatcher
matcher
)
{
this
.
context
=
context
;
this
.
matcher
=
matcher
;
}
void
matches
(
String
path
)
{
ServerWebExchange
exchange
=
webHandler
().
createExchange
(
MockServerHttpRequest
.
get
(
path
).
build
(),
new
MockServerHttpResponse
());
matches
(
exchange
);
}
private
void
matches
(
ServerWebExchange
exchange
)
{
assertThat
(
this
.
matcher
.
matches
(
exchange
).
block
().
isMatch
())
.
as
(
"Matches "
+
getRequestPath
(
exchange
)).
isTrue
();
}
void
doesNotMatch
(
String
path
)
{
ServerWebExchange
exchange
=
webHandler
().
createExchange
(
MockServerHttpRequest
.
get
(
path
).
build
(),
new
MockServerHttpResponse
());
doesNotMatch
(
exchange
);
}
private
void
doesNotMatch
(
ServerWebExchange
exchange
)
{
assertThat
(
this
.
matcher
.
matches
(
exchange
).
block
().
isMatch
())
.
as
(
"Does not match "
+
getRequestPath
(
exchange
)).
isFalse
();
}
private
TestHttpWebHandlerAdapter
webHandler
()
{
TestHttpWebHandlerAdapter
adapter
=
new
TestHttpWebHandlerAdapter
(
mock
(
WebHandler
.
class
));
adapter
.
setApplicationContext
(
this
.
context
);
return
adapter
;
}
private
String
getRequestPath
(
ServerWebExchange
exchange
)
{
return
exchange
.
getRequest
().
getPath
().
toString
();
}
}
private
static
class
TestHttpWebHandlerAdapter
extends
HttpWebHandlerAdapter
{
TestHttpWebHandlerAdapter
(
WebHandler
delegate
)
{
super
(
delegate
);
}
@Override
protected
ServerWebExchange
createExchange
(
ServerHttpRequest
request
,
ServerHttpResponse
response
)
{
return
super
.
createExchange
(
request
,
response
);
}
}
private
static
class
MockEndpointPathProvider
implements
EndpointPathProvider
{
@Override
public
List
<
String
>
getPaths
()
{
return
Arrays
.
asList
(
"/actuator/foo"
,
"/actuator/bar"
);
}
@Override
public
String
getPath
(
String
id
)
{
if
(
"foo"
.
equals
(
id
))
{
return
"/actuator/foo"
;
}
if
(
"bar"
.
equals
(
id
))
{
return
"/actuator/bar"
;
}
return
null
;
}
}
@Endpoint
(
id
=
"foo"
)
private
static
class
FooEndpoint
{
}
}
spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/EndpointRequestTests.java
→
spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/security/
servlet/
EndpointRequestTests.java
View file @
e57aafd6
...
...
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
actuate
.
autoconfigure
.
security
;
package
org
.
springframework
.
boot
.
actuate
.
autoconfigure
.
security
.
servlet
;
import
java.util.Arrays
;
import
java.util.List
;
...
...
spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/StaticResourceRequest.java
View file @
e57aafd6
...
...
@@ -27,7 +27,7 @@ import java.util.stream.Stream;
import
javax.servlet.http.HttpServletRequest
;
import
org.springframework.boot.autoconfigure.web.ServerProperties
;
import
org.springframework.boot.security.ApplicationContextRequestMatcher
;
import
org.springframework.boot.security.
servlet.
ApplicationContextRequestMatcher
;
import
org.springframework.security.web.util.matcher.AntPathRequestMatcher
;
import
org.springframework.security.web.util.matcher.OrRequestMatcher
;
import
org.springframework.security.web.util.matcher.RequestMatcher
;
...
...
spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc
View file @
e57aafd6
...
...
@@ -2882,6 +2882,17 @@ messages. Otherwise, the default password is not printed.
You can change the username and password by providing a `spring.security.user.name` and
`spring.security.user.password`.
The basic features you get by default in a web application are:
* A `UserDetailsService` (or `ReactiveUserDetailsService` in case of a WebFlux application)
bean with in-memory store and a single user with a generated password (see
{dc-spring-boot}/autoconfigure/security/SecurityProperties.User.html[`SecurityProperties.User`]
for the properties of the user).
* Form-based login or HTTP Basic security (depending on Content-Type) for the entire
application (including actuator endpoints if actuator is on the classpath).
== MVC Security
The default security configuration is implemented in `SecurityAutoConfiguration` and in
the classes imported from there (`SpringBootWebSecurityConfiguration` for web security
and `AuthenticationManagerConfiguration` for authentication configuration, which is also
...
...
@@ -2894,15 +2905,6 @@ To also switch off the authentication manager configuration, you can add a bean
There are several secure applications in the {github-code}/spring-boot-samples/[Spring
Boot samples] to get you started with common use cases.
The basic features you get by default in a web application are:
* A `UserDetailsService` bean with in-memory store and a single user with a generated
password (see
{dc-spring-boot}/autoconfigure/security/SecurityProperties.User.html[`SecurityProperties.User`]
for the properties of the user).
* Form-based login or HTTP Basic security (depending on Content-Type) for the entire
application (including actuator endpoints if actuator is on the classpath).
Access rules can be overridden by adding a custom `WebSecurityConfigurerAdapter`. Spring
Boot provides convenience methods that can be used to override access rules for actuator
endpoints and static resources. `EndpointRequest` can be used to create a `RequestMatcher`
...
...
@@ -2910,7 +2912,22 @@ that is based on the `management.endpoints.web.base-path` property.
`StaticResourceRequest` can be used to create a `RequestMatcher` for static resources in
commonly used locations.
== WebFlux Security
The default security configuration is implemented in `ReactiveSecurityAutoConfiguration` and in
the classes imported from there (`WebFluxSecurityConfiguration` for web security
and `ReactiveAuthenticationManagerConfiguration` for authentication configuration, which is also
relevant in non-web applications). To switch off the default web application security
configuration completely, you can add a bean of type `WebFilterChainProxy` (doing
so does not disable the authentication manager configuration or Actuator's security).
To also switch off the authentication manager configuration, you can add a bean of type
`ReactiveUserDetailsService` or `ReactiveAuthenticationManager`.
Access rules can be configured by adding a custom `SecurityWebFilterChain`. Spring
Boot provides convenience methods that can be used to override access rules for actuator
endpoints and static resources. `EndpointRequest` can be used to create a `ServerWebExchangeMatcher`
that is based on the `management.endpoints.web.base-path` property.
[[boot-features-security-oauth2]]
=== OAuth2
...
...
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/security/reactive/ApplicationContextServerWebExchangeMatcher.java
0 → 100644
View file @
e57aafd6
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
security
.
reactive
;
import
reactor.core.publisher.Mono
;
import
org.springframework.beans.factory.NoSuchBeanDefinitionException
;
import
org.springframework.beans.factory.config.AutowireCapableBeanFactory
;
import
org.springframework.context.ApplicationContext
;
import
org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher
;
import
org.springframework.util.Assert
;
import
org.springframework.web.server.ServerWebExchange
;
/**
* {@link ApplicationContext} backed {@link ServerWebExchangeMatcher}. Can work directly with the
* {@link ApplicationContext}, obtain an existing bean or
* {@link AutowireCapableBeanFactory#createBean(Class, int, boolean) create a new bean}
* that is autowired in the usual way.
*
* @param <C> The type of the context that the match method actually needs to use. Can be
* an {@link ApplicationContext}, a class of an {@link ApplicationContext#getBean(Class)
* existing bean} or a custom type that will be
* {@link AutowireCapableBeanFactory#createBean(Class, int, boolean) created} on demand.
* @author Madhura Bhave
* @since 2.0.0
*/
public
abstract
class
ApplicationContextServerWebExchangeMatcher
<
C
>
implements
ServerWebExchangeMatcher
{
private
final
Class
<?
extends
C
>
contextClass
;
private
C
context
;
private
Object
contextLock
=
new
Object
();
public
ApplicationContextServerWebExchangeMatcher
(
Class
<?
extends
C
>
contextClass
)
{
Assert
.
notNull
(
contextClass
,
"Context class must not be null"
);
this
.
contextClass
=
contextClass
;
}
@Override
public
final
Mono
<
MatchResult
>
matches
(
ServerWebExchange
exchange
)
{
return
matches
(
exchange
,
getContext
(
exchange
));
}
/**
* Decides whether the rule implemented by the strategy matches the supplied exchange.
* @param exchange the source exchange
* @param context the context instance
* @return if the exchange matches
*/
protected
abstract
Mono
<
MatchResult
>
matches
(
ServerWebExchange
exchange
,
C
context
);
protected
C
getContext
(
ServerWebExchange
exchange
)
{
if
(
this
.
context
==
null
)
{
synchronized
(
this
.
contextLock
)
{
this
.
context
=
createContext
(
exchange
);
initialized
(
this
.
context
);
}
}
return
this
.
context
;
}
/**
* Called once the context has been initialized.
* @param context the initialized context
*/
protected
void
initialized
(
C
context
)
{
}
@SuppressWarnings
(
"unchecked"
)
private
C
createContext
(
ServerWebExchange
exchange
)
{
ApplicationContext
context
=
exchange
.
getApplicationContext
();
if
(
context
==
null
)
{
throw
new
IllegalStateException
(
"No WebApplicationContext found."
);
}
if
(
this
.
contextClass
.
isInstance
(
context
))
{
return
(
C
)
context
;
}
try
{
return
context
.
getBean
(
this
.
contextClass
);
}
catch
(
NoSuchBeanDefinitionException
ex
)
{
return
(
C
)
context
.
getAutowireCapableBeanFactory
().
createBean
(
this
.
contextClass
,
AutowireCapableBeanFactory
.
AUTOWIRE_CONSTRUCTOR
,
false
);
}
}
}
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/security/ApplicationContextRequestMatcher.java
→
spring-boot-project/spring-boot/src/main/java/org/springframework/boot/security/
servlet/
ApplicationContextRequestMatcher.java
View file @
e57aafd6
...
...
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
security
;
package
org
.
springframework
.
boot
.
security
.
servlet
;
import
javax.servlet.http.HttpServletRequest
;
...
...
@@ -53,7 +53,7 @@ public abstract class ApplicationContextRequestMatcher<C> implements RequestMatc
}
@Override
public
boolean
matches
(
HttpServletRequest
request
)
{
public
final
boolean
matches
(
HttpServletRequest
request
)
{
return
matches
(
request
,
getContext
(
request
));
}
...
...
spring-boot-project/spring-boot/src/test/java/org/springframework/boot/security/reactive/ApplicationContextServerWebExchangeMatcherTests.java
0 → 100644
View file @
e57aafd6
/*
* Copyright 2012-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
security
.
reactive
;
import
org.junit.Rule
;
import
org.junit.Test
;
import
org.junit.rules.ExpectedException
;
import
reactor.core.publisher.Mono
;
import
org.springframework.context.ApplicationContext
;
import
org.springframework.context.support.StaticApplicationContext
;
import
org.springframework.http.server.reactive.ServerHttpRequest
;
import
org.springframework.http.server.reactive.ServerHttpResponse
;
import
org.springframework.mock.http.server.reactive.MockServerHttpRequest
;
import
org.springframework.mock.http.server.reactive.MockServerHttpResponse
;
import
org.springframework.mock.web.server.MockServerWebExchange
;
import
org.springframework.web.server.ServerWebExchange
;
import
org.springframework.web.server.WebHandler
;
import
org.springframework.web.server.adapter.HttpWebHandlerAdapter
;
import
static
org
.
assertj
.
core
.
api
.
Assertions
.
assertThat
;
import
static
org
.
mockito
.
Mockito
.
mock
;
/**
* Tests for {@link ApplicationContextServerWebExchangeMatcher}.
*
* @author Madhura Bhave
*/
public
class
ApplicationContextServerWebExchangeMatcherTests
{
@Rule
public
ExpectedException
thrown
=
ExpectedException
.
none
();
@Test
public
void
createWhenContextClassIsNullShouldThrowException
()
{
this
.
thrown
.
expect
(
IllegalArgumentException
.
class
);
this
.
thrown
.
expectMessage
(
"Context class must not be null"
);
new
TestApplicationContextServerWebExchangeMatcher
<>(
null
);
}
@Test
public
void
matchesWhenContextClassIsApplicationContextShouldProvideContext
()
{
ServerWebExchange
exchange
=
createHttpWebHandlerAdapter
();
StaticApplicationContext
context
=
(
StaticApplicationContext
)
exchange
.
getApplicationContext
();
assertThat
(
new
TestApplicationContextServerWebExchangeMatcher
<>(
ApplicationContext
.
class
)
.
callMatchesAndReturnProvidedContext
(
exchange
)).
isEqualTo
(
context
);
}
@Test
public
void
matchesWhenContextClassIsExistingBeanShouldProvideBean
()
{
ServerWebExchange
exchange
=
createHttpWebHandlerAdapter
();
StaticApplicationContext
context
=
(
StaticApplicationContext
)
exchange
.
getApplicationContext
();
context
.
registerSingleton
(
"existingBean"
,
ExistingBean
.
class
);
assertThat
(
new
TestApplicationContextServerWebExchangeMatcher
<>(
ExistingBean
.
class
)
.
callMatchesAndReturnProvidedContext
(
exchange
))
.
isEqualTo
(
context
.
getBean
(
ExistingBean
.
class
));
}
@Test
public
void
matchesWhenContextClassIsNewBeanShouldProvideBean
()
{
ServerWebExchange
exchange
=
createHttpWebHandlerAdapter
();
StaticApplicationContext
context
=
(
StaticApplicationContext
)
exchange
.
getApplicationContext
();
context
.
registerSingleton
(
"existingBean"
,
ExistingBean
.
class
);
assertThat
(
new
TestApplicationContextServerWebExchangeMatcher
<>(
NewBean
.
class
)
.
callMatchesAndReturnProvidedContext
(
exchange
).
getBean
())
.
isEqualTo
(
context
.
getBean
(
ExistingBean
.
class
));
}
@Test
public
void
matchesWhenContextIsNull
()
{
MockServerWebExchange
exchange
=
MockServerWebExchange
.
from
(
MockServerHttpRequest
.
get
(
"/path"
).
build
());
this
.
thrown
.
expect
(
IllegalStateException
.
class
);
this
.
thrown
.
expectMessage
(
"No WebApplicationContext found."
);
new
TestApplicationContextServerWebExchangeMatcher
<>(
ExistingBean
.
class
)
.
callMatchesAndReturnProvidedContext
(
exchange
);
}
private
ServerWebExchange
createHttpWebHandlerAdapter
()
{
StaticApplicationContext
context
=
new
StaticApplicationContext
();
TestHttpWebHandlerAdapter
adapter
=
new
TestHttpWebHandlerAdapter
(
mock
(
WebHandler
.
class
));
adapter
.
setApplicationContext
(
context
);
return
adapter
.
createExchange
(
MockServerHttpRequest
.
get
(
"/path"
).
build
(),
new
MockServerHttpResponse
());
}
static
class
TestHttpWebHandlerAdapter
extends
HttpWebHandlerAdapter
{
TestHttpWebHandlerAdapter
(
WebHandler
delegate
)
{
super
(
delegate
);
}
@Override
protected
ServerWebExchange
createExchange
(
ServerHttpRequest
request
,
ServerHttpResponse
response
)
{
return
super
.
createExchange
(
request
,
response
);
}
}
static
class
ExistingBean
{
}
static
class
NewBean
{
private
final
ExistingBean
bean
;
NewBean
(
ExistingBean
bean
)
{
this
.
bean
=
bean
;
}
public
ExistingBean
getBean
()
{
return
this
.
bean
;
}
}
static
class
TestApplicationContextServerWebExchangeMatcher
<
C
>
extends
ApplicationContextServerWebExchangeMatcher
<
C
>
{
private
C
providedContext
;
TestApplicationContextServerWebExchangeMatcher
(
Class
<?
extends
C
>
context
)
{
super
(
context
);
}
C
callMatchesAndReturnProvidedContext
(
ServerWebExchange
exchange
)
{
matches
(
exchange
);
return
getProvidedContext
();
}
@Override
protected
Mono
<
MatchResult
>
matches
(
ServerWebExchange
exchange
,
C
context
)
{
this
.
providedContext
=
context
;
return
MatchResult
.
match
();
}
C
getProvidedContext
()
{
return
this
.
providedContext
;
}
}
}
spring-boot-project/spring-boot/src/test/java/org/springframework/boot/security/ApplicationContextRequestMatcherTests.java
→
spring-boot-project/spring-boot/src/test/java/org/springframework/boot/security/
servlet/
ApplicationContextRequestMatcherTests.java
View file @
e57aafd6
...
...
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package
org
.
springframework
.
boot
.
security
;
package
org
.
springframework
.
boot
.
security
.
servlet
;
import
javax.servlet.http.HttpServletRequest
;
...
...
spring-boot-samples/spring-boot-sample-actuator-custom-security/src/main/java/sample/actuator/customsecurity/SecurityConfiguration.java
View file @
e57aafd6
...
...
@@ -16,7 +16,7 @@
package
sample
.
actuator
.
customsecurity
;
import
org.springframework.boot.actuate.autoconfigure.security.EndpointRequest
;
import
org.springframework.boot.actuate.autoconfigure.security.
servlet.
EndpointRequest
;
import
org.springframework.boot.autoconfigure.security.StaticResourceRequest
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
...
...
spring-boot-samples/spring-boot-sample-secure-webflux/src/main/resources/application.properties
View file @
e57aafd6
spring.security.user.name
=
user
spring.security.user.password
=
password
management.endpoints.web.expose
=
*
\ No newline at end of file
spring-boot-samples/spring-boot-sample-secure-webflux/src/test/java/sample/secure/webflux/SampleSecureWebFluxCustomSecurityTests.java
0 → 100644
View file @
e57aafd6
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package
sample
.
secure
.
webflux
;
import
java.util.Base64
;
import
org.junit.Test
;
import
org.junit.runner.RunWith
;
import
org.springframework.beans.factory.annotation.Autowired
;
import
org.springframework.boot.actuate.autoconfigure.security.reactive.EndpointRequest
;
import
org.springframework.boot.test.context.SpringBootTest
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.http.HttpStatus
;
import
org.springframework.http.MediaType
;
import
org.springframework.security.config.web.server.ServerHttpSecurity
;
import
org.springframework.security.core.userdetails.MapReactiveUserDetailsService
;
import
org.springframework.security.core.userdetails.User
;
import
org.springframework.security.web.server.SecurityWebFilterChain
;
import
org.springframework.test.context.junit4.SpringRunner
;
import
org.springframework.test.web.reactive.server.WebTestClient
;
/**
* Integration tests for a secure reactive application with custom security.
*
* @author Madhura Bhave
*/
@RunWith
(
SpringRunner
.
class
)
@SpringBootTest
(
webEnvironment
=
SpringBootTest
.
WebEnvironment
.
RANDOM_PORT
,
classes
=
{
SampleSecureWebFluxCustomSecurityTests
.
SecurityConfiguration
.
class
,
SampleSecureWebFluxApplication
.
class
})
public
class
SampleSecureWebFluxCustomSecurityTests
{
@Autowired
private
WebTestClient
webClient
;
@Test
public
void
userDefinedMappingsSecure
()
{
this
.
webClient
.
get
().
uri
(
"/"
).
accept
(
MediaType
.
APPLICATION_JSON
).
exchange
()
.
expectStatus
().
isEqualTo
(
HttpStatus
.
UNAUTHORIZED
);
}
@Test
public
void
healthAndInfoDontRequireAuthentication
()
{
this
.
webClient
.
get
().
uri
(
"/actuator/health"
).
accept
(
MediaType
.
APPLICATION_JSON
)
.
exchange
().
expectStatus
().
isOk
();
this
.
webClient
.
get
().
uri
(
"/actuator/info"
).
accept
(
MediaType
.
APPLICATION_JSON
)
.
exchange
().
expectStatus
().
isOk
();
}
@Test
public
void
actuatorsSecuredByRole
()
{
this
.
webClient
.
get
().
uri
(
"/actuator/env"
).
accept
(
MediaType
.
APPLICATION_JSON
)
.
header
(
"Authorization"
,
"basic "
+
getBasicAuth
()).
exchange
()
.
expectStatus
().
isForbidden
();
}
@Test
public
void
actuatorsAccessibleOnCorrectLogin
()
{
this
.
webClient
.
get
().
uri
(
"/actuator/env"
).
accept
(
MediaType
.
APPLICATION_JSON
)
.
header
(
"Authorization"
,
"basic "
+
getBasicAuthForAdmin
()).
exchange
()
.
expectStatus
().
isOk
();
}
@Configuration
static
class
SecurityConfiguration
{
@Bean
public
MapReactiveUserDetailsService
userDetailsService
()
{
return
new
MapReactiveUserDetailsService
(
User
.
withDefaultPasswordEncoder
().
username
(
"user"
).
password
(
"password"
)
.
authorities
(
"ROLE_USER"
).
build
(),
User
.
withDefaultPasswordEncoder
().
username
(
"admin"
).
password
(
"admin"
)
.
authorities
(
"ROLE_ACTUATOR"
,
"ROLE_USER"
).
build
());
}
@Bean
SecurityWebFilterChain
springSecurityFilterChain
(
ServerHttpSecurity
http
)
{
http
.
authorizeExchange
()
.
matchers
(
EndpointRequest
.
to
(
"health"
,
"info"
)).
permitAll
()
.
matchers
(
EndpointRequest
.
toAnyEndpoint
()).
hasRole
(
"ACTUATOR"
)
.
pathMatchers
(
"/login"
).
permitAll
()
.
anyExchange
().
authenticated
()
.
and
()
.
httpBasic
();
return
http
.
build
();
}
}
private
String
getBasicAuth
()
{
return
new
String
(
Base64
.
getEncoder
().
encode
((
"user:password"
).
getBytes
()));
}
private
String
getBasicAuthForAdmin
()
{
return
new
String
(
Base64
.
getEncoder
().
encode
((
"admin:admin"
).
getBytes
()));
}
}
spring-boot-samples/spring-boot-sample-web-method-security/src/main/java/sample/security/method/SampleMethodSecurityApplication.java
View file @
e57aafd6
...
...
@@ -19,7 +19,7 @@ package sample.security.method;
import
java.util.Date
;
import
java.util.Map
;
import
org.springframework.boot.actuate.autoconfigure.security.EndpointRequest
;
import
org.springframework.boot.actuate.autoconfigure.security.
servlet.
EndpointRequest
;
import
org.springframework.boot.autoconfigure.SpringBootApplication
;
import
org.springframework.boot.builder.SpringApplicationBuilder
;
import
org.springframework.context.annotation.Bean
;
...
...
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