2018-03-06 12:12:49 -05:00
[[secure-object-impls]]
2021-07-30 14:52:15 -04:00
= Secure Object Implementations
2018-03-06 12:12:49 -05:00
2021-04-21 17:01:26 -04:00
This section covers how Spring Security handles Secure Object implementations.
2018-03-06 12:12:49 -05:00
[[aop-alliance]]
2021-07-30 14:52:15 -04:00
== AOP Alliance (MethodInvocation) Security Interceptor
2021-04-21 17:01:26 -04:00
Prior to Spring Security 2.0, securing `MethodInvocation` instances needed a lot of boiler plate configuration.
2021-09-21 15:56:09 -04:00
Now the recommended approach for method security is to use xref:servlet/configuration/xml-namespace.adoc#ns-method-security[namespace configuration].
2021-04-21 17:01:26 -04:00
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.
2018-03-06 12:12:49 -05:00
2021-04-21 17:01:26 -04:00
Method security is enforced by using a `MethodSecurityInterceptor`, which secures `MethodInvocation` instances.
2018-03-06 12:12:49 -05:00
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.
2021-04-21 17:01:26 -04:00
Other implementations are used to handle annotation-based configuration.
2018-03-06 12:12:49 -05:00
2021-07-30 14:52:15 -04:00
=== Explicit MethodSecurityInterceptor Configuration
2021-04-21 17:01:26 -04:00
You can configure a `MethodSecurityInterceptor` directly in your application context for use with one of Spring AOP's proxying mechanisms:
2018-03-06 12:12:49 -05:00
2021-04-21 17:01:26 -04:00
====
2018-03-06 12:12:49 -05:00
[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>
----
2021-04-21 17:01:26 -04:00
====
2018-03-06 12:12:49 -05:00
[[aspectj]]
2021-07-30 14:52:15 -04:00
== AspectJ (JoinPoint) Security Interceptor
2018-03-06 12:12:49 -05:00
The AspectJ security interceptor is very similar to the AOP Alliance security interceptor discussed in the previous section.
2021-04-21 17:01:26 -04:00
We discuss only the differences in this section.
2018-03-06 12:12:49 -05:00
The AspectJ interceptor is named `AspectJSecurityInterceptor`.
2021-04-21 17:01:26 -04:00
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.
2018-03-06 12:12:49 -05:00
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.
2021-04-21 17:01:26 -04:00
We first consider how the `AspectJSecurityInterceptor` is configured in the Spring application context:
2018-03-06 12:12:49 -05:00
2021-04-21 17:01:26 -04:00
====
2018-03-06 12:12:49 -05:00
[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>
----
2021-04-21 17:01:26 -04:00
====
2018-03-06 12:12:49 -05:00
2021-04-21 17:01:26 -04:00
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.
2018-03-06 12:12:49 -05:00
2021-04-21 17:01:26 -04:00
Next, you need to define an AspectJ `aspect`, as the following example shows:
2018-03-06 12:12:49 -05:00
2021-04-21 17:01:26 -04:00
====
2018-03-06 12:12:49 -05:00
[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");
}
}
}
----
2021-04-21 17:01:26 -04:00
====
2018-03-06 12:12:49 -05:00
2021-04-21 17:01:26 -04:00
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).
2018-03-06 12:12:49 -05:00
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.
2021-04-21 17:01:26 -04:00
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:
2018-03-06 12:12:49 -05:00
2021-04-21 17:01:26 -04:00
====
2018-03-06 12:12:49 -05:00
[source,xml]
----
<bean id="domainObjectInstanceSecurityAspect"
class="security.samples.aspectj.DomainObjectInstanceSecurityAspect"
factory-method="aspectOf">
<property name="securityInterceptor" ref="bankManagerSecurity"/>
</bean>
----
2021-04-21 17:01:26 -04:00
====
2018-03-06 12:12:49 -05:00
2021-04-21 17:01:26 -04:00
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.