mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-03-01 10:59:16 +00:00
Revisit Request and Method Security Docs
Issue gh-13088
This commit is contained in:
parent
42cd19fcee
commit
e5fcf1ebcf
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 182 KiB |
@ -59,9 +59,7 @@
|
|||||||
** xref:servlet/authorization/index.adoc[Authorization]
|
** xref:servlet/authorization/index.adoc[Authorization]
|
||||||
*** xref:servlet/authorization/architecture.adoc[Authorization Architecture]
|
*** xref:servlet/authorization/architecture.adoc[Authorization Architecture]
|
||||||
*** xref:servlet/authorization/authorize-http-requests.adoc[Authorize HTTP Requests]
|
*** xref:servlet/authorization/authorize-http-requests.adoc[Authorize HTTP Requests]
|
||||||
*** xref:servlet/authorization/authorize-requests.adoc[Authorize HTTP Requests with FilterSecurityInterceptor]
|
|
||||||
*** xref:servlet/authorization/expression-based.adoc[Expression-Based Access Control]
|
*** xref:servlet/authorization/expression-based.adoc[Expression-Based Access Control]
|
||||||
*** xref:servlet/authorization/secure-objects.adoc[Secure Object Implementations]
|
|
||||||
*** xref:servlet/authorization/method-security.adoc[Method Security]
|
*** xref:servlet/authorization/method-security.adoc[Method Security]
|
||||||
*** xref:servlet/authorization/acls.adoc[Domain Object Security ACLs]
|
*** xref:servlet/authorization/acls.adoc[Domain Object Security ACLs]
|
||||||
*** xref:servlet/authorization/events.adoc[Authorization Events]
|
*** xref:servlet/authorization/events.adoc[Authorization Events]
|
||||||
|
@ -36,7 +36,7 @@ There are no further migrations steps for Java or Kotlin for this feature.
|
|||||||
== Use `AuthorizationManager` for Request Security
|
== Use `AuthorizationManager` for Request Security
|
||||||
|
|
||||||
In 6.0, `<http>` defaults `once-per-request` to `false`, `filter-all-dispatcher-types` to `true`, and `use-authorization-manager` to `true`.
|
In 6.0, `<http>` defaults `once-per-request` to `false`, `filter-all-dispatcher-types` to `true`, and `use-authorization-manager` to `true`.
|
||||||
Also, xref:servlet/authorization/authorize-requests.adoc#filtersecurityinterceptor-every-request[`authorizeRequests#filterSecurityInterceptorOncePerRequest`] defaults to `false` and xref:servlet/authorization/authorize-http-requests.adoc[`authorizeHttpRequests#filterAllDispatcherTypes`] defaults to `true`.
|
Also, {security-api-url}org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.AbstractInterceptUrlRegistry.html#filterSecurityInterceptorOncePerRequest(boolean)[`authorizeRequests#filterSecurityInterceptorOncePerRequest`] defaults to `false` and xref:servlet/authorization/authorize-http-requests.adoc[`authorizeHttpRequests#filterAllDispatcherTypes`] defaults to `true`.
|
||||||
So, to complete migration, any defaults values can be removed.
|
So, to complete migration, any defaults values can be removed.
|
||||||
|
|
||||||
For example, if you opted in to the 6.0 default for `filter-all-dispatcher-types` or `authorizeHttpRequests#filterAllDispatcherTypes` like so:
|
For example, if you opted in to the 6.0 default for `filter-all-dispatcher-types` or `authorizeHttpRequests#filterAllDispatcherTypes` like so:
|
||||||
|
@ -194,7 +194,7 @@ The following is a comprehensive list of Spring Security Filter ordering:
|
|||||||
* `OAuth2AuthorizationCodeGrantFilter`
|
* `OAuth2AuthorizationCodeGrantFilter`
|
||||||
* `SessionManagementFilter`
|
* `SessionManagementFilter`
|
||||||
* <<servlet-exceptiontranslationfilter,`ExceptionTranslationFilter`>>
|
* <<servlet-exceptiontranslationfilter,`ExceptionTranslationFilter`>>
|
||||||
* xref:servlet/authorization/authorize-requests.adoc#servlet-authorization-filtersecurityinterceptor[`FilterSecurityInterceptor`]
|
* xref:servlet/authorization/authorize-http-requests.adoc[`AuthorizationFilter`]
|
||||||
* `SwitchUserFilter`
|
* `SwitchUserFilter`
|
||||||
|
|
||||||
[[servlet-exceptiontranslationfilter]]
|
[[servlet-exceptiontranslationfilter]]
|
||||||
|
@ -15,7 +15,7 @@ The preceding figure builds off our xref:servlet/architecture.adoc#servlet-secur
|
|||||||
|
|
||||||
image:{icondir}/number_1.png[] First, a user makes an unauthenticated request to the resource `/private` for which it is not authorized.
|
image:{icondir}/number_1.png[] First, a user makes an unauthenticated request to the resource `/private` for which it is not authorized.
|
||||||
|
|
||||||
image:{icondir}/number_2.png[] Spring Security's xref:servlet/authorization/authorize-requests.adoc#servlet-authorization-filtersecurityinterceptor[`FilterSecurityInterceptor`] indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`.
|
image:{icondir}/number_2.png[] Spring Security's xref:servlet/authorization/authorize-http-requests.adoc[`AuthorizationFilter`] indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`.
|
||||||
|
|
||||||
image:{icondir}/number_3.png[] Since the user is not authenticated, xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] initiates __Start Authentication__.
|
image:{icondir}/number_3.png[] Since the user is not authenticated, xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] initiates __Start Authentication__.
|
||||||
The configured xref:servlet/authentication/architecture.adoc#servlet-authentication-authenticationentrypoint[`AuthenticationEntryPoint`] is an instance of {security-api-url}org/springframework/security/web/authentication/www/BasicAuthenticationEntryPoint.html[`BasicAuthenticationEntryPoint`], which sends a WWW-Authenticate header.
|
The configured xref:servlet/authentication/architecture.adoc#servlet-authentication-authenticationentrypoint[`AuthenticationEntryPoint`] is an instance of {security-api-url}org/springframework/security/web/authentication/www/BasicAuthenticationEntryPoint.html[`BasicAuthenticationEntryPoint`], which sends a WWW-Authenticate header.
|
||||||
|
@ -16,7 +16,7 @@ The preceding figure builds off our xref:servlet/architecture.adoc#servlet-secur
|
|||||||
|
|
||||||
image:{icondir}/number_1.png[] First, a user makes an unauthenticated request to the resource (`/private`) for which it is not authorized.
|
image:{icondir}/number_1.png[] First, a user makes an unauthenticated request to the resource (`/private`) for which it is not authorized.
|
||||||
|
|
||||||
image:{icondir}/number_2.png[] Spring Security's xref:servlet/authorization/authorize-requests.adoc#servlet-authorization-filtersecurityinterceptor[`FilterSecurityInterceptor`] indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`.
|
image:{icondir}/number_2.png[] Spring Security's xref:servlet/authorization/authorize-http-requests.adoc[`AuthorizationFilter`] indicates that the unauthenticated request is __Denied__ by throwing an `AccessDeniedException`.
|
||||||
|
|
||||||
image:{icondir}/number_3.png[] Since the user is not authenticated, xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] initiates __Start Authentication__ and sends a redirect to the login page with the configured xref:servlet/authentication/architecture.adoc#servlet-authentication-authenticationentrypoint[`AuthenticationEntryPoint`].
|
image:{icondir}/number_3.png[] Since the user is not authenticated, xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] initiates __Start Authentication__ and sends a redirect to the login page with the configured xref:servlet/authentication/architecture.adoc#servlet-authentication-authenticationentrypoint[`AuthenticationEntryPoint`].
|
||||||
In most cases, the `AuthenticationEntryPoint` is an instance of {security-api-url}org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.html[`LoginUrlAuthenticationEntryPoint`].
|
In most cases, the `AuthenticationEntryPoint` is an instance of {security-api-url}org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.html[`LoginUrlAuthenticationEntryPoint`].
|
||||||
|
@ -23,30 +23,76 @@ String getAuthority();
|
|||||||
----
|
----
|
||||||
====
|
====
|
||||||
|
|
||||||
This method lets an
|
This method is used by an
|
||||||
`AccessDecisionManager` instance to obtain a precise `String` representation of the `GrantedAuthority`.
|
`AuthorizationManager` instance to obtain a precise `String` representation of the `GrantedAuthority`.
|
||||||
By returning a representation as a `String`, a `GrantedAuthority` can be easily "`read`" by most `AccessDecisionManager` implementations.
|
By returning a representation as a `String`, a `GrantedAuthority` can be easily "read" by most `AuthorizationManager` implementations.
|
||||||
If a `GrantedAuthority` cannot be precisely represented as a `String`, the `GrantedAuthority` is considered "`complex`" and `getAuthority()` must return `null`.
|
If a `GrantedAuthority` cannot be precisely represented as a `String`, the `GrantedAuthority` is considered "complex" and `getAuthority()` must return `null`.
|
||||||
|
|
||||||
An example of a "`complex`" `GrantedAuthority` would be an implementation that stores a list of operations and authority thresholds that apply to different customer account numbers.
|
An example of a complex `GrantedAuthority` would be an implementation that stores a list of operations and authority thresholds that apply to different customer account numbers.
|
||||||
Representing this complex `GrantedAuthority` as a `String` would be quite difficult. As a result, the `getAuthority()` method should return `null`.
|
Representing this complex `GrantedAuthority` as a `String` would be quite difficult. As a result, the `getAuthority()` method should return `null`.
|
||||||
This indicates to any `AccessDecisionManager` that it needs to support the specific `GrantedAuthority` implementation to understand its contents.
|
This indicates to any `AuthorizationManager` that it needs to support the specific `GrantedAuthority` implementation to understand its contents.
|
||||||
|
|
||||||
Spring Security includes one concrete `GrantedAuthority` implementation: `SimpleGrantedAuthority`.
|
Spring Security includes one concrete `GrantedAuthority` implementation: `SimpleGrantedAuthority`.
|
||||||
This implementation lets any user-specified `String` be converted into a `GrantedAuthority`.
|
This implementation lets any user-specified `String` be converted into a `GrantedAuthority`.
|
||||||
All `AuthenticationProvider` instances included with the security architecture use `SimpleGrantedAuthority` to populate the `Authentication` object.
|
All `AuthenticationProvider` instances included with the security architecture use `SimpleGrantedAuthority` to populate the `Authentication` object.
|
||||||
|
|
||||||
|
[[jc-method-security-custom-granted-authority-defaults]]
|
||||||
|
By default, role-based authorization rules include `ROLE_` as a prefix.
|
||||||
|
This means that if there is an authorization rule that requires a security context to have a role of "USER", Spring Security will by default look for a `GrantedAuthority#getAuthority` that returns "ROLE_USER".
|
||||||
|
|
||||||
|
You can customize this with `GrantedAuthorityDefaults`.
|
||||||
|
`GrantedAuthorityDefaults` exists to allow customizing the prefix to use for role-based authorization rules.
|
||||||
|
|
||||||
|
You can configure the authorization rules to use a different prefix by exposing a `GrantedAuthorityDefaults` bean, like so:
|
||||||
|
|
||||||
|
.Custom MethodSecurityExpressionHandler
|
||||||
|
====
|
||||||
|
.Java
|
||||||
|
[source,java,role="primary"]
|
||||||
|
----
|
||||||
|
@Bean
|
||||||
|
static GrantedAuthorityDefaults grantedAuthorityDefaults() {
|
||||||
|
return new GrantedAuthorityDefaults("MYPREFIX_");
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
.Kotlin
|
||||||
|
[source,kotlin,role="secondary"]
|
||||||
|
----
|
||||||
|
companion object {
|
||||||
|
@Bean
|
||||||
|
fun grantedAuthorityDefaults() : GrantedAuthorityDefaults {
|
||||||
|
return GrantedAuthorityDefaults("MYPREFIX_");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
.Xml
|
||||||
|
[source,xml,role="secondary"]
|
||||||
|
----
|
||||||
|
<bean id="grantedAuthorityDefaults" class="org.springframework.security.config.core.GrantedAuthorityDefaults">
|
||||||
|
<constructor-arg value="MYPREFIX_"/>
|
||||||
|
</bean>
|
||||||
|
----
|
||||||
|
====
|
||||||
|
|
||||||
|
[TIP]
|
||||||
|
====
|
||||||
|
You expose `GrantedAuthorityDefaults` using a `static` method to ensure that Spring publishes it before it initializes Spring Security's method security `@Configuration` classes
|
||||||
|
====
|
||||||
|
|
||||||
[[authz-pre-invocation]]
|
[[authz-pre-invocation]]
|
||||||
== Pre-Invocation Handling
|
== Invocation Handling
|
||||||
Spring Security provides interceptors that control access to secure objects, such as method invocations or web requests.
|
Spring Security provides interceptors that control access to secure objects, such as method invocations or web requests.
|
||||||
A pre-invocation decision on whether the invocation is allowed to proceed is made by the `AccessDecisionManager`.
|
A pre-invocation decision on whether the invocation is allowed to proceed is made by `AuthorizationManager` instances.
|
||||||
|
Also post-invocation decisions on whether a given value may be returned is made by `AuthorizationManager` instances.
|
||||||
|
|
||||||
=== The AuthorizationManager
|
=== The AuthorizationManager
|
||||||
`AuthorizationManager` supersedes both <<authz-legacy-note,`AccessDecisionManager` and `AccessDecisionVoter`>>.
|
`AuthorizationManager` supersedes both <<authz-legacy-note,`AccessDecisionManager` and `AccessDecisionVoter`>>.
|
||||||
|
|
||||||
Applications that customize an `AccessDecisionManager` or `AccessDecisionVoter` are encouraged to <<authz-voter-adaptation,change to using `AuthorizationManager`>>.
|
Applications that customize an `AccessDecisionManager` or `AccessDecisionVoter` are encouraged to <<authz-voter-adaptation,change to using `AuthorizationManager`>>.
|
||||||
|
|
||||||
``AuthorizationManager``s are called by the xref:servlet/authorization/authorize-http-requests.adoc[`AuthorizationFilter`] and are responsible for making final access control decisions.
|
``AuthorizationManager``s are called by Spring Security's xref:servlet/authorization/authorize-http-requests.adoc[request-based], xref:servlet/authorization/method-security.adoc[method-based], and xref:servlet/integrations/websocket.adoc[message-based] authorization components and are responsible for making final access control decisions.
|
||||||
The `AuthorizationManager` interface contains two methods:
|
The `AuthorizationManager` interface contains two methods:
|
||||||
|
|
||||||
====
|
====
|
||||||
@ -97,6 +143,10 @@ Another manager is the `AuthenticatedAuthorizationManager`.
|
|||||||
It can be used to differentiate between anonymous, fully-authenticated and remember-me authenticated users.
|
It can be used to differentiate between anonymous, fully-authenticated and remember-me authenticated users.
|
||||||
Many sites allow certain limited access under remember-me authentication, but require a user to confirm their identity by logging in for full access.
|
Many sites allow certain limited access under remember-me authentication, but require a user to confirm their identity by logging in for full access.
|
||||||
|
|
||||||
|
[[authz-authorization-managers]]
|
||||||
|
==== AuthorizationManagers
|
||||||
|
There are also helpful static factories in `AuthenticationManagers` for composing individual ``AuthenticationManager``s into more sophisticated expressions.
|
||||||
|
|
||||||
[[authz-custom-authorization-manager]]
|
[[authz-custom-authorization-manager]]
|
||||||
==== Custom Authorization Managers
|
==== Custom Authorization Managers
|
||||||
Obviously, you can also implement a custom `AuthorizationManager` and you can put just about any access-control logic you want in it.
|
Obviously, you can also implement a custom `AuthorizationManager` and you can put just about any access-control logic you want in it.
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,183 +0,0 @@
|
|||||||
[[servlet-authorization-filtersecurityinterceptor]]
|
|
||||||
= Authorize HttpServletRequest with FilterSecurityInterceptor
|
|
||||||
:figures: servlet/authorization
|
|
||||||
|
|
||||||
[NOTE]
|
|
||||||
====
|
|
||||||
`FilterSecurityInterceptor` is in the process of being replaced by xref:servlet/authorization/authorize-http-requests.adoc[`AuthorizationFilter`].
|
|
||||||
Consider using that instead.
|
|
||||||
====
|
|
||||||
|
|
||||||
This section builds on xref:servlet/architecture.adoc#servlet-architecture[Servlet Architecture and Implementation] by digging deeper into how xref:servlet/authorization/index.adoc#servlet-authorization[authorization] works within Servlet-based applications.
|
|
||||||
|
|
||||||
The {security-api-url}org/springframework/security/web/access/intercept/FilterSecurityInterceptor.html[`FilterSecurityInterceptor`] provides xref:servlet/authorization/index.adoc#servlet-authorization[authorization] for `HttpServletRequest` instances.
|
|
||||||
It is inserted into the xref:servlet/architecture.adoc#servlet-filterchainproxy[FilterChainProxy] as one of the xref:servlet/architecture.adoc#servlet-security-filters[Security Filters].
|
|
||||||
|
|
||||||
The following image shows the role of `FilterSecurityInterceptor`:
|
|
||||||
|
|
||||||
.Authorize HttpServletRequest
|
|
||||||
image::{figures}/filtersecurityinterceptor.png[]
|
|
||||||
|
|
||||||
image:{icondir}/number_1.png[] The `FilterSecurityInterceptor` obtains an xref:servlet/authentication/architecture.adoc#servlet-authentication-authentication[Authentication] from the xref:servlet/authentication/architecture.adoc#servlet-authentication-securitycontextholder[SecurityContextHolder].
|
|
||||||
image:{icondir}/number_2.png[] `FilterSecurityInterceptor` creates a {security-api-url}org/springframework/security/web/FilterInvocation.html[`FilterInvocation`] from the `HttpServletRequest`, `HttpServletResponse`, and `FilterChain` that are passed into the `FilterSecurityInterceptor`.
|
|
||||||
image:{icondir}/number_3.png[] It passes the `FilterInvocation` to `SecurityMetadataSource` to get the ``ConfigAttribute``s.
|
|
||||||
image:{icondir}/number_4.png[] It passes the `Authentication`, `FilterInvocation`, and ``ConfigAttribute``s to the `AccessDecisionManager`.
|
|
||||||
image:{icondir}/number_5.png[] If authorization is denied, an `AccessDeniedException` is thrown.
|
|
||||||
In this case, the xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] handles the `AccessDeniedException`.
|
|
||||||
image:{icondir}/number_6.png[] If access is granted, `FilterSecurityInterceptor` continues with the xref:servlet/architecture.adoc#servlet-filters-review[`FilterChain`], which lets the application process normally.
|
|
||||||
|
|
||||||
// configuration (xml/java)
|
|
||||||
|
|
||||||
By default, Spring Security's authorization requires all requests to be authenticated.
|
|
||||||
The following listing shows the explicit configuration:
|
|
||||||
|
|
||||||
[[servlet-authorize-requests-defaults]]
|
|
||||||
.Every Request Must be Authenticated
|
|
||||||
====
|
|
||||||
.Java
|
|
||||||
[source,java,role="primary"]
|
|
||||||
----
|
|
||||||
@Bean
|
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
|
||||||
http
|
|
||||||
// ...
|
|
||||||
.authorizeRequests(authorize -> authorize
|
|
||||||
.anyRequest().authenticated()
|
|
||||||
);
|
|
||||||
return http.build();
|
|
||||||
}
|
|
||||||
----
|
|
||||||
|
|
||||||
.XML
|
|
||||||
[source,xml,role="secondary"]
|
|
||||||
----
|
|
||||||
<http>
|
|
||||||
<!-- ... -->
|
|
||||||
<intercept-url pattern="/**" access="authenticated"/>
|
|
||||||
</http>
|
|
||||||
----
|
|
||||||
|
|
||||||
.Kotlin
|
|
||||||
[source,kotlin,role="secondary"]
|
|
||||||
----
|
|
||||||
@Bean
|
|
||||||
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
|
|
||||||
http {
|
|
||||||
// ...
|
|
||||||
authorizeRequests {
|
|
||||||
authorize(anyRequest, authenticated)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return http.build()
|
|
||||||
}
|
|
||||||
----
|
|
||||||
====
|
|
||||||
|
|
||||||
We can configure Spring Security to have different rules by adding more rules in order of precedence:
|
|
||||||
|
|
||||||
.Authorize Requests
|
|
||||||
====
|
|
||||||
.Java
|
|
||||||
[source,java,role="primary"]
|
|
||||||
----
|
|
||||||
@Bean
|
|
||||||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
|
|
||||||
http
|
|
||||||
// ...
|
|
||||||
.authorizeRequests(authorize -> authorize // <1>
|
|
||||||
.requestMatchers("/resources/**", "/signup", "/about").permitAll() // <2>
|
|
||||||
.requestMatchers("/admin/**").hasRole("ADMIN") // <3>
|
|
||||||
.requestMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')") // <4>
|
|
||||||
.anyRequest().denyAll() // <5>
|
|
||||||
);
|
|
||||||
return http.build();
|
|
||||||
}
|
|
||||||
----
|
|
||||||
|
|
||||||
.XML
|
|
||||||
[source,xml,role="secondary"]
|
|
||||||
----
|
|
||||||
<http> <!--1-->
|
|
||||||
<!-- ... -->
|
|
||||||
<!--2-->
|
|
||||||
<intercept-url pattern="/resources/**" access="permitAll"/>
|
|
||||||
<intercept-url pattern="/signup" access="permitAll"/>
|
|
||||||
<intercept-url pattern="/about" access="permitAll"/>
|
|
||||||
|
|
||||||
<intercept-url pattern="/admin/**" access="hasRole('ADMIN')"/> <!--3-->
|
|
||||||
<intercept-url pattern="/db/**" access="hasRole('ADMIN') and hasRole('DBA')"/> <!--4-->
|
|
||||||
<intercept-url pattern="/**" access="denyAll"/> <!--5-->
|
|
||||||
</http>
|
|
||||||
----
|
|
||||||
|
|
||||||
.Kotlin
|
|
||||||
[source,kotlin,role="secondary"]
|
|
||||||
----
|
|
||||||
@Bean
|
|
||||||
open fun filterChain(http: HttpSecurity): SecurityFilterChain {
|
|
||||||
http {
|
|
||||||
authorizeRequests { // <1>
|
|
||||||
authorize("/resources/**", permitAll) // <2>
|
|
||||||
authorize("/signup", permitAll)
|
|
||||||
authorize("/about", permitAll)
|
|
||||||
|
|
||||||
authorize("/admin/**", hasRole("ADMIN")) // <3>
|
|
||||||
authorize("/db/**", "hasRole('ADMIN') and hasRole('DBA')") // <4>
|
|
||||||
authorize(anyRequest, denyAll) // <5>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return http.build()
|
|
||||||
}
|
|
||||||
----
|
|
||||||
====
|
|
||||||
<1> There are multiple authorization rules specified.
|
|
||||||
Each rule is considered in the order they were declared.
|
|
||||||
<2> We specified multiple URL patterns that any user can access.
|
|
||||||
Specifically, any user can access a request if the URL starts with "/resources/", equals "/signup", or equals "/about".
|
|
||||||
<3> Any URL that starts with "/admin/" will be restricted to users who have the role "ROLE_ADMIN".
|
|
||||||
You will notice that since we are invoking the `hasRole` method we do not need to specify the "ROLE_" prefix.
|
|
||||||
<4> Any URL that starts with "/db/" requires the user to have both "ROLE_ADMIN" and "ROLE_DBA".
|
|
||||||
You will notice that since we are using the `hasRole` expression we do not need to specify the "ROLE_" prefix.
|
|
||||||
<5> Any URL that has not already been matched on is denied access.
|
|
||||||
This is a good strategy if you do not want to accidentally forget to update your authorization rules.
|
|
||||||
====
|
|
||||||
|
|
||||||
|
|
||||||
[[filtersecurityinterceptor-every-request]]
|
|
||||||
== Configure FilterSecurityInterceptor with Dispatcher Types
|
|
||||||
|
|
||||||
By default, the `FilterSecurityInterceptor` applies to every request.
|
|
||||||
This means that if a request is dispatched from a request that was already filtered, the `FilterSecurityInterceptor` will perform the same authorization checks on the dispatched request.
|
|
||||||
In some scenarios, you may not want to apply authorization on some dispatcher types:
|
|
||||||
|
|
||||||
.Permit ASYNC and ERROR dispatcher types
|
|
||||||
====
|
|
||||||
.Java
|
|
||||||
[source,java,role="primary"]
|
|
||||||
----
|
|
||||||
@Bean
|
|
||||||
SecurityFilterChain web(HttpSecurity http) throws Exception {
|
|
||||||
http
|
|
||||||
.authorizeRequests((authorize) -> authorize
|
|
||||||
.dispatcherTypeMatchers(DispatcherType.ASYNC, DispatcherType.ERROR).permitAll()
|
|
||||||
.anyRequest.authenticated()
|
|
||||||
)
|
|
||||||
// ...
|
|
||||||
|
|
||||||
return http.build();
|
|
||||||
}
|
|
||||||
----
|
|
||||||
.XML
|
|
||||||
[source,xml]
|
|
||||||
----
|
|
||||||
<http auto-config="true">
|
|
||||||
<intercept-url request-matcher-ref="dispatcherTypeMatcher" access="permitAll" />
|
|
||||||
<intercept-url pattern="/**" access="authenticated"/>
|
|
||||||
</http>
|
|
||||||
|
|
||||||
<b:bean id="dispatcherTypeMatcher" class="org.springframework.security.web.util.matcher.DispatcherTypeRequestMatcher">
|
|
||||||
<b:constructor-arg value="ASYNC"/>
|
|
||||||
<b:constructor-arg value="ERROR"/>
|
|
||||||
</b:bean>
|
|
||||||
----
|
|
||||||
====
|
|
@ -2,11 +2,12 @@
|
|||||||
= Authorization
|
= Authorization
|
||||||
:page-section-summary-toc: 1
|
:page-section-summary-toc: 1
|
||||||
|
|
||||||
|
Having established xref:servlet/authentication/index.adoc[how users will authenticate], you also need to configure your application's authorization rules.
|
||||||
|
|
||||||
The advanced authorization capabilities within Spring Security represent one of the most compelling reasons for its popularity.
|
The advanced authorization capabilities within Spring Security represent one of the most compelling reasons for its popularity.
|
||||||
Irrespective of how you choose to authenticate (whether using a Spring Security-provided mechanism and provider or integrating with a container or other non-Spring Security authentication authority), the authorization services can be used within your application in a consistent and simple way.
|
Irrespective of how you choose to authenticate (whether using a Spring Security-provided mechanism and provider or integrating with a container or other non-Spring Security authentication authority), the authorization services can be used within your application in a consistent and simple way.
|
||||||
|
|
||||||
In this part, we explore the different `AbstractSecurityInterceptor` implementations, which were introduced in Part I.
|
You should consider attaching authorization rules to xref:servlet/authorization/authorize-http-requests.adoc[request URIs] and xref:servlet/authorization/method-security.adoc[methods] to begin.
|
||||||
We then move on to explore how to fine-tune authorization through the use of domain access control lists.
|
Below there is also wealth of detail about xref:servlet/authorization/architecture.adoc[how Spring Security authorization works] and how, having established a basic model, it can be fine-tuned.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,143 +0,0 @@
|
|||||||
|
|
||||||
[[secure-object-impls]]
|
|
||||||
= Secure Object Implementations
|
|
||||||
|
|
||||||
This section covers how Spring Security handles Secure Object implementations.
|
|
||||||
|
|
||||||
[[aop-alliance]]
|
|
||||||
== AOP Alliance (MethodInvocation) Security Interceptor
|
|
||||||
Prior to Spring Security 2.0, securing `MethodInvocation` instances needed a lot of boiler plate configuration.
|
|
||||||
Now the recommended approach for method security is to use xref:servlet/configuration/xml-namespace.adoc#ns-method-security[namespace configuration].
|
|
||||||
This way, the method security infrastructure beans are configured automatically for you, so you need not know about the implementation classes.
|
|
||||||
We provide only a quick overview of the classes that are involved here.
|
|
||||||
|
|
||||||
Method security is enforced by using a `MethodSecurityInterceptor`, which secures `MethodInvocation` instances.
|
|
||||||
Depending on the configuration approach, an interceptor may be specific to a single bean or shared between multiple beans.
|
|
||||||
The interceptor uses a `MethodSecurityMetadataSource` instance to obtain the configuration attributes that apply to a particular method invocation.
|
|
||||||
`MapBasedMethodSecurityMetadataSource` is used to store configuration attributes keyed by method names (which can be wildcarded) and will be used internally when the attributes are defined in the application context using the `<intercept-methods>` or `<protect-point>` elements.
|
|
||||||
Other implementations are used to handle annotation-based configuration.
|
|
||||||
|
|
||||||
=== Explicit MethodSecurityInterceptor Configuration
|
|
||||||
You can configure a `MethodSecurityInterceptor` directly in your application context for use with one of Spring AOP's proxying mechanisms:
|
|
||||||
|
|
||||||
====
|
|
||||||
[source,xml]
|
|
||||||
----
|
|
||||||
<bean id="bankManagerSecurity" class=
|
|
||||||
"org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor">
|
|
||||||
<property name="authenticationManager" ref="authenticationManager"/>
|
|
||||||
<property name="accessDecisionManager" ref="accessDecisionManager"/>
|
|
||||||
<property name="afterInvocationManager" ref="afterInvocationManager"/>
|
|
||||||
<property name="securityMetadataSource">
|
|
||||||
<sec:method-security-metadata-source>
|
|
||||||
<sec:protect method="com.mycompany.BankManager.delete*" access="ROLE_SUPERVISOR"/>
|
|
||||||
<sec:protect method="com.mycompany.BankManager.getBalance" access="ROLE_TELLER,ROLE_SUPERVISOR"/>
|
|
||||||
</sec:method-security-metadata-source>
|
|
||||||
</property>
|
|
||||||
</bean>
|
|
||||||
----
|
|
||||||
====
|
|
||||||
|
|
||||||
[[aspectj]]
|
|
||||||
== AspectJ (JoinPoint) Security Interceptor
|
|
||||||
The AspectJ security interceptor is very similar to the AOP Alliance security interceptor discussed in the previous section.
|
|
||||||
We discuss only the differences in this section.
|
|
||||||
|
|
||||||
The AspectJ interceptor is named `AspectJSecurityInterceptor`.
|
|
||||||
Unlike the AOP Alliance security interceptor, which relies on the Spring application context to weave in the security interceptor through proxying, the `AspectJSecurityInterceptor` is woven in through the AspectJ compiler.
|
|
||||||
It would not be uncommon to use both types of security interceptors in the same application, with `AspectJSecurityInterceptor` being used for domain object instance security and the AOP Alliance `MethodSecurityInterceptor` being used for services layer security.
|
|
||||||
|
|
||||||
We first consider how the `AspectJSecurityInterceptor` is configured in the Spring application context:
|
|
||||||
|
|
||||||
====
|
|
||||||
[source,xml]
|
|
||||||
----
|
|
||||||
<bean id="bankManagerSecurity" class=
|
|
||||||
"org.springframework.security.access.intercept.aspectj.AspectJMethodSecurityInterceptor">
|
|
||||||
<property name="authenticationManager" ref="authenticationManager"/>
|
|
||||||
<property name="accessDecisionManager" ref="accessDecisionManager"/>
|
|
||||||
<property name="afterInvocationManager" ref="afterInvocationManager"/>
|
|
||||||
<property name="securityMetadataSource">
|
|
||||||
<sec:method-security-metadata-source>
|
|
||||||
<sec:protect method="com.mycompany.BankManager.delete*" access="ROLE_SUPERVISOR"/>
|
|
||||||
<sec:protect method="com.mycompany.BankManager.getBalance" access="ROLE_TELLER,ROLE_SUPERVISOR"/>
|
|
||||||
</sec:method-security-metadata-source>
|
|
||||||
</property>
|
|
||||||
</bean>
|
|
||||||
----
|
|
||||||
====
|
|
||||||
|
|
||||||
The two interceptors can share the same `securityMetadataSource`, as the `SecurityMetadataSource` works with `java.lang.reflect.Method` instances rather than an AOP library-specific class.
|
|
||||||
Your access decisions have access to the relevant AOP library-specific invocation (`MethodInvocation` or `JoinPoint`) and can consider a range of additional criteria (such as method arguments) when making access decisions.
|
|
||||||
|
|
||||||
Next, you need to define an AspectJ `aspect`, as the following example shows:
|
|
||||||
|
|
||||||
====
|
|
||||||
[source,java]
|
|
||||||
----
|
|
||||||
|
|
||||||
package org.springframework.security.samples.aspectj;
|
|
||||||
|
|
||||||
import org.springframework.security.access.intercept.aspectj.AspectJSecurityInterceptor;
|
|
||||||
import org.springframework.security.access.intercept.aspectj.AspectJCallback;
|
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
|
|
||||||
public aspect DomainObjectInstanceSecurityAspect implements InitializingBean {
|
|
||||||
|
|
||||||
private AspectJSecurityInterceptor securityInterceptor;
|
|
||||||
|
|
||||||
pointcut domainObjectInstanceExecution(): target(PersistableEntity)
|
|
||||||
&& execution(public * *(..)) && !within(DomainObjectInstanceSecurityAspect);
|
|
||||||
|
|
||||||
Object around(): domainObjectInstanceExecution() {
|
|
||||||
if (this.securityInterceptor == null) {
|
|
||||||
return proceed();
|
|
||||||
}
|
|
||||||
|
|
||||||
AspectJCallback callback = new AspectJCallback() {
|
|
||||||
public Object proceedWithObject() {
|
|
||||||
return proceed();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return this.securityInterceptor.invoke(thisJoinPoint, callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AspectJSecurityInterceptor getSecurityInterceptor() {
|
|
||||||
return securityInterceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSecurityInterceptor(AspectJSecurityInterceptor securityInterceptor) {
|
|
||||||
this.securityInterceptor = securityInterceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void afterPropertiesSet() throws Exception {
|
|
||||||
if (this.securityInterceptor == null)
|
|
||||||
throw new IllegalArgumentException("securityInterceptor required");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
----
|
|
||||||
====
|
|
||||||
|
|
||||||
|
|
||||||
In the preceding example, the security interceptor is applied to every instance of `PersistableEntity`, which is an abstract class not shown (you can use any other class or `pointcut` expression you like).
|
|
||||||
For those curious, `AspectJCallback` is needed because the `proceed();` statement has special meaning only within an `around()` body.
|
|
||||||
The `AspectJSecurityInterceptor` calls this anonymous `AspectJCallback` class when it wants the target object to continue.
|
|
||||||
|
|
||||||
You need to configure Spring to load the aspect and wire it with the `AspectJSecurityInterceptor`.
|
|
||||||
The following example shows a bean declaration that achieves this:
|
|
||||||
|
|
||||||
====
|
|
||||||
[source,xml]
|
|
||||||
----
|
|
||||||
|
|
||||||
<bean id="domainObjectInstanceSecurityAspect"
|
|
||||||
class="security.samples.aspectj.DomainObjectInstanceSecurityAspect"
|
|
||||||
factory-method="aspectOf">
|
|
||||||
<property name="securityInterceptor" ref="bankManagerSecurity"/>
|
|
||||||
</bean>
|
|
||||||
----
|
|
||||||
====
|
|
||||||
|
|
||||||
Now you can create your beans from anywhere within your application, using whatever means you think fit (e.g. `new Person();`), and they have the security interceptor applied.
|
|
@ -27,7 +27,7 @@ The figure above builds off our xref:servlet/architecture.adoc#servlet-securityf
|
|||||||
|
|
||||||
image:{icondir}/number_1.png[] First, a user makes an unauthenticated request to the `/private` resource for which the user is not authorized.
|
image:{icondir}/number_1.png[] First, a user makes an unauthenticated request to the `/private` resource for which the user is not authorized.
|
||||||
|
|
||||||
image:{icondir}/number_2.png[] Spring Security's xref:servlet/authorization/authorize-requests.adoc#servlet-authorization-filtersecurityinterceptor[`FilterSecurityInterceptor`] indicates that the unauthenticated request is _Denied_ by throwing an `AccessDeniedException`.
|
image:{icondir}/number_2.png[] Spring Security's xref:servlet/authorization/authorize-http-requests.adoc[`AuthorizationFilter`] indicates that the unauthenticated request is _Denied_ by throwing an `AccessDeniedException`.
|
||||||
|
|
||||||
image:{icondir}/number_3.png[] Since the user is not authenticated, xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] initiates _Start Authentication_.
|
image:{icondir}/number_3.png[] Since the user is not authenticated, xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] initiates _Start Authentication_.
|
||||||
The configured xref:servlet/authentication/architecture.adoc#servlet-authentication-authenticationentrypoint[`AuthenticationEntryPoint`] is an instance of {security-api-url}org/springframework/security/oauth2/server/resource/authentication/BearerTokenAuthenticationEntryPoint.html[`BearerTokenAuthenticationEntryPoint`], which sends a `WWW-Authenticate` header.
|
The configured xref:servlet/authentication/architecture.adoc#servlet-authentication-authenticationentrypoint[`AuthenticationEntryPoint`] is an instance of {security-api-url}org/springframework/security/oauth2/server/resource/authentication/BearerTokenAuthenticationEntryPoint.html[`BearerTokenAuthenticationEntryPoint`], which sends a `WWW-Authenticate` header.
|
||||||
|
@ -16,7 +16,7 @@ The figure above builds off our xref:servlet/architecture.adoc#servlet-securityf
|
|||||||
|
|
||||||
image:{icondir}/number_1.png[] First, a user makes an unauthenticated request to the `/private` resource, for which it is not authorized.
|
image:{icondir}/number_1.png[] First, a user makes an unauthenticated request to the `/private` resource, for which it is not authorized.
|
||||||
|
|
||||||
image:{icondir}/number_2.png[] Spring Security's xref:servlet/authorization/authorize-requests.adoc#servlet-authorization-filtersecurityinterceptor[`FilterSecurityInterceptor`] indicates that the unauthenticated request is _Denied_ by throwing an `AccessDeniedException`.
|
image:{icondir}/number_2.png[] Spring Security's xref:servlet/authorization/authorize-http-requests.adoc[`AuthorizationFilter`] indicates that the unauthenticated request is _Denied_ by throwing an `AccessDeniedException`.
|
||||||
|
|
||||||
image:{icondir}/number_3.png[] Since the user lacks authorization, the xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] initiates _Start Authentication_.
|
image:{icondir}/number_3.png[] Since the user lacks authorization, the xref:servlet/architecture.adoc#servlet-exceptiontranslationfilter[`ExceptionTranslationFilter`] initiates _Start Authentication_.
|
||||||
The configured xref:servlet/authentication/architecture.adoc#servlet-authentication-authenticationentrypoint[`AuthenticationEntryPoint`] is an instance of {security-api-url}org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.html[`LoginUrlAuthenticationEntryPoint`], which redirects to <<servlet-saml2login-sp-initiated-factory,the `<saml2:AuthnRequest>` generating endpoint>>, `Saml2WebSsoAuthenticationRequestFilter`.
|
The configured xref:servlet/authentication/architecture.adoc#servlet-authentication-authenticationentrypoint[`AuthenticationEntryPoint`] is an instance of {security-api-url}org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.html[`LoginUrlAuthenticationEntryPoint`], which redirects to <<servlet-saml2login-sp-initiated-factory,the `<saml2:AuthnRequest>` generating endpoint>>, `Saml2WebSsoAuthenticationRequestFilter`.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user