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
Hide 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 @@
...
@@ -14,7 +14,7 @@
* limitations under the License.
* 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.ArrayList
;
import
java.util.Arrays
;
import
java.util.Arrays
;
...
@@ -28,10 +28,9 @@ import java.util.stream.Stream;
...
@@ -28,10 +28,9 @@ import java.util.stream.Stream;
import
javax.servlet.http.HttpServletRequest
;
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.autoconfigure.endpoint.web.EndpointPathProvider
;
import
org.springframework.boot.actuate.endpoint.annotation.Endpoint
;
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.core.annotation.AnnotationUtils
;
import
org.springframework.security.web.util.matcher.AntPathRequestMatcher
;
import
org.springframework.security.web.util.matcher.AntPathRequestMatcher
;
import
org.springframework.security.web.util.matcher.OrRequestMatcher
;
import
org.springframework.security.web.util.matcher.OrRequestMatcher
;
...
@@ -172,16 +171,6 @@ public final class EndpointRequest {
...
@@ -172,16 +171,6 @@ public final class EndpointRequest {
.
collect
(
Collectors
.
toList
());
.
collect
(
Collectors
.
toList
());
}
}
@Override
public
boolean
matches
(
HttpServletRequest
request
)
{
try
{
return
super
.
matches
(
request
);
}
catch
(
BeanCreationException
ex
)
{
return
false
;
}
}
@Override
@Override
protected
boolean
matches
(
HttpServletRequest
request
,
protected
boolean
matches
(
HttpServletRequest
request
,
EndpointPathProvider
context
)
{
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 @@
...
@@ -14,7 +14,7 @@
* limitations under the License.
* 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.Arrays
;
import
java.util.List
;
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;
...
@@ -27,7 +27,7 @@ import java.util.stream.Stream;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletRequest
;
import
org.springframework.boot.autoconfigure.web.ServerProperties
;
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.AntPathRequestMatcher
;
import
org.springframework.security.web.util.matcher.OrRequestMatcher
;
import
org.springframework.security.web.util.matcher.OrRequestMatcher
;
import
org.springframework.security.web.util.matcher.RequestMatcher
;
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.
...
@@ -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
You can change the username and password by providing a `spring.security.user.name` and
`spring.security.user.password`.
`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 default security configuration is implemented in `SecurityAutoConfiguration` and in
the classes imported from there (`SpringBootWebSecurityConfiguration` for web security
the classes imported from there (`SpringBootWebSecurityConfiguration` for web security
and `AuthenticationManagerConfiguration` for authentication configuration, which is also
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
...
@@ -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
There are several secure applications in the {github-code}/spring-boot-samples/[Spring
Boot samples] to get you started with common use cases.
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
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
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`
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.
...
@@ -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
`StaticResourceRequest` can be used to create a `RequestMatcher` for static resources in
commonly used locations.
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]]
[[boot-features-security-oauth2]]
=== 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 @@
...
@@ -14,7 +14,7 @@
* limitations under the License.
* limitations under the License.
*/
*/
package
org
.
springframework
.
boot
.
security
;
package
org
.
springframework
.
boot
.
security
.
servlet
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletRequest
;
...
@@ -53,7 +53,7 @@ public abstract class ApplicationContextRequestMatcher<C> implements RequestMatc
...
@@ -53,7 +53,7 @@ public abstract class ApplicationContextRequestMatcher<C> implements RequestMatc
}
}
@Override
@Override
public
boolean
matches
(
HttpServletRequest
request
)
{
public
final
boolean
matches
(
HttpServletRequest
request
)
{
return
matches
(
request
,
getContext
(
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 @@
...
@@ -14,7 +14,7 @@
* limitations under the License.
* limitations under the License.
*/
*/
package
org
.
springframework
.
boot
.
security
;
package
org
.
springframework
.
boot
.
security
.
servlet
;
import
javax.servlet.http.HttpServletRequest
;
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 @@
...
@@ -16,7 +16,7 @@
package
sample
.
actuator
.
customsecurity
;
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.boot.autoconfigure.security.StaticResourceRequest
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
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.name
=
user
spring.security.user.password
=
password
spring.security.user.password
=
password
\ No newline at end of file
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;
...
@@ -19,7 +19,7 @@ package sample.security.method;
import
java.util.Date
;
import
java.util.Date
;
import
java.util.Map
;
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.autoconfigure.SpringBootApplication
;
import
org.springframework.boot.builder.SpringApplicationBuilder
;
import
org.springframework.boot.builder.SpringApplicationBuilder
;
import
org.springframework.context.annotation.Bean
;
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