AspectJ (JoinPoint) Security Interceptor

The AspectJ security interceptor is very similar to the AOP Alliance security interceptor discussed in the previous section. Indeed we will only discuss 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 via proxying, the AspectJSecurityInterceptor is weaved in via 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.

Let's first consider how the AspectJSecurityInterceptor is configured in the Spring application context:

<bean id="bankManagerSecurity"
        class="org.springframework.security.intercept.method.aspectj.AspectJSecurityInterceptor">
  <property name="authenticationManager" ref="authenticationManager"/>
  <property name="accessDecisionManager" ref="accessDecisionManager"/>
  <property name="afterInvocationManager" ref="afterInvocationManager"/>
  <property name="objectDefinitionSource">
    <value>
        org.springframework.security.context.BankManager.delete*=ROLE_SUPERVISOR
        org.springframework.security.context.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR
    </value>
</property>
</bean>        

As you can see, aside from the class name, the AspectJSecurityInterceptor is exactly the same as the AOP Alliance security interceptor. Indeed the two interceptors can share the same objectDefinitionSource, as the ObjectDefinitionSource works with java.lang.reflect.Methods rather than an AOP library-specific class. Of course, your access decisions have access to the relevant AOP library-specific invocation (ie MethodInvocation or JoinPoint) and as such can consider a range of addition criteria when making access decisions (such as method arguments).

Next you'll need to define an AspectJ aspect. For example:

package org.springframework.security.samples.aspectj;

import org.springframework.security.intercept.method.aspectj.AspectJSecurityInterceptor;
import org.springframework.security.intercept.method.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 above example, the security interceptor will be 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 will need to configure Spring to load the aspect and wire it with the AspectJSecurityInterceptor. A bean declaration which achieves this is shown below:

<bean id="domainObjectInstanceSecurityAspect"
     class="org.springframework.security.samples.aspectj.DomainObjectInstanceSecurityAspect"
     factory-method="aspectOf">
  <property name="securityInterceptor" ref="aspectJSecurityInterceptor"/>
</bean>
    

That's it! Now you can create your beans from anywhere within your application, using whatever means you think fit (eg new Person();) and they will have the security interceptor applied.