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/architecture.adoc[Authorization Architecture]
|
||||
*** 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/secure-objects.adoc[Secure Object Implementations]
|
||||
*** xref:servlet/authorization/method-security.adoc[Method Security]
|
||||
*** xref:servlet/authorization/acls.adoc[Domain Object Security ACLs]
|
||||
*** 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
|
||||
|
||||
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.
|
||||
|
||||
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`
|
||||
* `SessionManagementFilter`
|
||||
* <<servlet-exceptiontranslationfilter,`ExceptionTranslationFilter`>>
|
||||
* xref:servlet/authorization/authorize-requests.adoc#servlet-authorization-filtersecurityinterceptor[`FilterSecurityInterceptor`]
|
||||
* xref:servlet/authorization/authorize-http-requests.adoc[`AuthorizationFilter`]
|
||||
* `SwitchUserFilter`
|
||||
|
||||
[[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_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__.
|
||||
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_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`].
|
||||
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
|
||||
`AccessDecisionManager` 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.
|
||||
If a `GrantedAuthority` cannot be precisely represented as a `String`, the `GrantedAuthority` is considered "`complex`" and `getAuthority()` must return `null`.
|
||||
This method is used by an
|
||||
`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 `AuthorizationManager` implementations.
|
||||
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`.
|
||||
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`.
|
||||
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.
|
||||
|
||||
[[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]]
|
||||
== Pre-Invocation Handling
|
||||
== Invocation Handling
|
||||
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
|
||||
`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`>>.
|
||||
|
||||
``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:
|
||||
|
||||
====
|
||||
@ -97,6 +143,10 @@ Another manager is the `AuthenticatedAuthorizationManager`.
|
||||
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.
|
||||
|
||||
[[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]]
|
||||
==== 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.
|
||||
|
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
|
||||
: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.
|
||||
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.
|
||||
We then move on to explore how to fine-tune authorization through the use of domain access control lists.
|
||||
|
||||
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.
|
||||
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_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_.
|
||||
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_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_.
|
||||
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