Secure Object Implementations

23.1. AOP Alliance (MethodInvocation) Security Interceptor

Prior to Spring Security 2.0, securing MethodInvocations needed quite a lot of boiler plate configuration. Now the recommended approach for method security is to use namespace configuration. This way the method security infrastructure beans are configured automatically for you so you don't really need to know about the implementation classes. We'll just provide a quick overview of the classes that are involved here.

Method security in enforced using a MethodSecurityInterceptor, which secures MethodInvocations. Depending on the configuration approach, an interceptor may be specific to a single bean or shared between multiple beans. The interceptor uses a MethodDefinitionSource instance to obtain the configuration attributes that apply to a particular method invocation. MapBasedMethodDefinitionSource 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 will be used to handle annotation-based configuration.

23.1.1. Explicit MethodSecurityIterceptor Configuration

You can of course configure a MethodSecurityIterceptor directly in your application context for use with one of Spring AOP's proxying mechanisms:

  
<bean id="bankManagerSecurity"
    class="org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor">
  <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>    

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

23.3. FilterInvocation Security Interceptor

To secure FilterInvocations, developers need to add a FilterSecurityInterceptor to their filter chain. A typical configuration example is provided below:

In the application context you will need to configure three beans:

 

<bean id="exceptionTranslationFilter"
        class="org.springframework.security.ui.ExceptionTranslationFilter">
  <property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>
</bean>

<bean id="authenticationEntryPoint"
        class="org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint">
  <property name="loginFormUrl" value="/acegilogin.jsp"/>
  <property name="forceHttps" value="false"/>
</bean>

<bean id="filterSecurityInterceptor"
        class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
  <property name="authenticationManager" ref="authenticationManager"/>
  <property name="accessDecisionManager" ref="accessDecisionManager"/>
  <property name="objectDefinitionSource">
    <security:filter-invocation-definition-source>
      <security:intercept-url pattern="/secure/super/**" access="ROLE_WE_DONT_HAVE"/>
      <security:intercept-url pattern="/secure/**" access="ROLE_SUPERVISOR,ROLE_TELLER"/>    
    </security:filter-invocation-definition-source>                
  </property>
</bean>         

The ExceptionTranslationFilter provides the bridge between Java exceptions and HTTP responses. It is solely concerned with maintaining the user interface. This filter does not do any actual security enforcement. If an AuthenticationException is detected, the filter will call the AuthenticationEntryPoint to commence the authentication process (e.g. a user login).

The AuthenticationEntryPoint will be called if the user requests a secure HTTP resource but they are not authenticated. The class handles presenting the appropriate response to the user so that authentication can begin. Three concrete implementations are provided with Spring Security: AuthenticationProcessingFilterEntryPoint for commencing a form-based authentication, BasicProcessingFilterEntryPoint for commencing a HTTP Basic authentication process, and CasProcessingFilterEntryPoint for commencing a JA-SIG Central Authentication Service (CAS) login. The AuthenticationProcessingFilterEntryPoint and CasProcessingFilterEntryPoint have optional properties related to forcing the use of HTTPS, so please refer to the JavaDocs if you require this.

FilterSecurityInterceptor is responsible for handling the security of HTTP resources. Like any other security interceptor, it requires a reference to an AuthenticationManager and an AccessDecisionManager, which are both discussed in separate sections below. The FilterSecurityInterceptor is also configured with configuration attributes that apply to different HTTP URL requests. A full discussion of configuration attributes is provided in the High Level Design section of this document.

The FilterSecurityInterceptor can be configured with configuration attributes in two ways. The first, which is shown above, is using the <filter-invocation-definition-source> namespace element. This is similar to the <filter-chain-map> used to configure a FilterChainProxy but the <intercept-url> child elements only use the pattern and access attributes. The second is by writing your own ObjectDefinitionSource, although this is beyond the scope of this document. Irrespective of the approach used, the ObjectDefinitionSource is responsible for returning a ConfigAttributeDefinition object that contains all of the configuration attributes associated with a single secure HTTP URL.

It should be noted that the FilterSecurityInterceptor.setObjectDefinitionSource() method actually expects an instance of FilterInvocationDefinitionSource. This is a marker interface which subclasses ObjectDefinitionSource. It simply denotes the ObjectDefinitionSource understands FilterInvocations. In the interests of simplicity we'll continue to refer to the FilterInvocationDefinitionSource as an ObjectDefinitionSource, as the distinction is of little relevance to most users of the FilterSecurityInterceptor.

When using the namespace option to configure the interceptor, commas are used to delimit the different configuration attributes that apply to each HTTP URL. Each configuration attribute is assigned into its own SecurityConfig object. The SecurityConfig object is discussed in the High Level Design section. The ObjectDefinitionSource created by the property editor, FilterInvocationDefinitionSource, matches configuration attributes against FilterInvocations based on expression evaluation of the request URL. Two standard expression syntaxes are supported. The default is to treat all expressions as Apache Ant paths and regular expressions are also supported for ore complex cases. The path-type attribute is used to specify the type of pattern being used. It is not possible to mix expression syntaxes within the same definition. For example, the previous configuration using regular expressions instead of Ant paths would be written as follows:

<bean id="filterInvocationInterceptor"
        class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
  <property name="authenticationManager" ref="authenticationManager"/>
  <property name="accessDecisionManager" ref="accessDecisionManager"/>
  <property name="runAsManager" ref="runAsManager"/>
  <property name="objectDefinitionSource">
    <security:filter-invocation-definition-source path-type="regex">
      <security:intercept-url pattern="\A/secure/super/.*\Z" access="ROLE_WE_DONT_HAVE"/>
      <security:intercept-url pattern="\A/secure/.*\" access="ROLE_SUPERVISOR,ROLE_TELLER"/>
    </security:filter-invocation-definition-source>  
  </property>
</bean>        

Irrespective of the type of expression syntax used, expressions are always evaluated in the order they are defined. Thus it is important that more specific expressions are defined higher in the list than less specific expressions. This is reflected in our example above, where the more specific /secure/super/ pattern appears higher than the less specific /secure/ pattern. If they were reversed, the /secure/ pattern would always match and the /secure/super/ pattern would never be evaluated.

As with other security interceptors, the validateConfigAttributes property is observed. When set to true (the default), at startup time the FilterSecurityInterceptor will evaluate if the provided configuration attributes are valid. It does this by checking each configuration attribute can be processed by either the AccessDecisionManager or the RunAsManager. If neither of these can process a given configuration attribute, an exception is thrown.