spring-security/docs/modules/ROOT/pages/servlet/authorization/secure-objects.adoc

144 lines
6.6 KiB
Plaintext

[[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.