Spring Security
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

148 lines
7.9 KiB

<chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="secure-object-impls"
xmlns:xlink="http://www.w3.org/1999/xlink">
<info>
<title>Secure Object Implementations</title>
</info>
<section xml:id="aop-alliance">
<info>
<title>AOP Alliance (MethodInvocation) Security Interceptor</title>
</info>
<para> Prior to Spring Security 2.0, securing <classname>MethodInvocation</classname>s needed
quite a lot of boiler plate configuration. Now the recommended approach for method security is
to use <link xlink:href="#ns-method-security">namespace configuration</link>. 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. </para>
<para> Method security in enforced using a <classname>MethodSecurityInterceptor</classname>,
which secures <classname>MethodInvocation</classname>s. Depending on the configuration
approach, an interceptor may be specific to a single bean or shared between multiple beans.
The interceptor uses a <interfacename>MethodDefinitionSource</interfacename> instance to
obtain the configuration attributes that apply to a particular method invocation.
<classname>MapBasedMethodDefinitionSource</classname> 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
<literal>&lt;intercept-methods&gt;</literal> or <literal>&lt;protect-point&gt;</literal>
elements. Other implementations will be used to handle annotation-based configuration. </para>
<section>
<title>Explicit MethodSecurityInterceptor Configuration</title>
<para> You can of course configure a <classname>MethodSecurityIterceptor</classname> directly
in your application context for use with one of Spring AOP's proxying mechanisms: <programlisting><![CDATA[
<bean id="bankManagerSecurity"
class="org.springframework.security.intercept.aopalliance.MethodSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="afterInvocationManager" ref="afterInvocationManager"/>
<property name="securityMetadataSource">
<value>
com.mycompany.BankManager.delete*=ROLE_SUPERVISOR
com.mycompany.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR
</value>
</property>
</bean> ]]>
</programlisting></para>
</section>
</section>
<section xml:id="aspectj">
<info>
<title>AspectJ (JoinPoint) Security Interceptor</title>
</info>
<para>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.</para>
<para>The AspectJ interceptor is named <literal>AspectJSecurityInterceptor</literal>. Unlike the
AOP Alliance security interceptor, which relies on the Spring application context to weave in
the security interceptor via proxying, the <literal>AspectJSecurityInterceptor</literal> is
weaved in via the AspectJ compiler. It would not be uncommon to use both types of security
interceptors in the same application, with <literal>AspectJSecurityInterceptor</literal> being
used for domain object instance security and the AOP Alliance
<classname>MethodSecurityInterceptor</classname> being used for services layer
security.</para>
<para>Let's first consider how the <literal>AspectJSecurityInterceptor</literal> is configured
in the Spring application context:</para>
<programlisting><![CDATA[
<bean id="bankManagerSecurity"
class="org.springframework.security.intercept.aspectj.AspectJSecurityInterceptor">
<property name="authenticationManager" ref="authenticationManager"/>
<property name="accessDecisionManager" ref="accessDecisionManager"/>
<property name="afterInvocationManager" ref="afterInvocationManager"/>
<property name="securityMetadataSource">
<value>
com.mycompany.BankManager.delete*=ROLE_SUPERVISOR
com.mycompany.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR
</value>
</property>
</bean>]]> </programlisting>
<para>As you can see, aside from the class name, the
<literal>AspectJSecurityInterceptor</literal> is exactly the same as the AOP Alliance
security interceptor. Indeed the two interceptors can share the same
<literal>securityMetadataSource</literal>, as the
<interfacename>SecurityMetadataSource</interfacename> works with
<literal>java.lang.reflect.Method</literal>s rather than an AOP library-specific class. Of
course, your access decisions have access to the relevant AOP library-specific invocation (ie
<classname>MethodInvocation</classname> or <literal>JoinPoint</literal>) and as such can
consider a range of addition criteria when making access decisions (such as method
arguments).</para>
<para>Next you'll need to define an AspectJ <literal>aspect</literal>. For example:</para>
<programlisting language="java">
package org.springframework.security.samples.aspectj;
import org.springframework.security.intercept.aspectj.AspectJSecurityInterceptor;
import org.springframework.security.intercept.aspectj.AspectJCallback;
import org.springframework.beans.factory.InitializingBean;
public aspect DomainObjectInstanceSecurityAspect implements InitializingBean {
private AspectJSecurityInterceptor securityInterceptor;
pointcut domainObjectInstanceExecution(): target(PersistableEntity)
&amp;&amp; execution(public * *(..)) &amp;&amp; !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");
}
}</programlisting>
<para>In the above example, the security interceptor will be applied to every instance of
<literal>PersistableEntity</literal>, which is an abstract class not shown (you can use any
other class or <literal>pointcut</literal> expression you like). For those curious,
<literal>AspectJCallback</literal> is needed because the <literal>proceed();</literal>
statement has special meaning only within an <literal>around()</literal> body. The
<literal>AspectJSecurityInterceptor</literal> calls this anonymous
<literal>AspectJCallback</literal> class when it wants the target object to continue.</para>
<para>You will need to configure Spring to load the aspect and wire it with the
<literal>AspectJSecurityInterceptor</literal>. A bean declaration which achieves this is
shown below:</para>
<programlisting><![CDATA[
<bean id="domainObjectInstanceSecurityAspect"
class="org.springframework.security.samples.aspectj.DomainObjectInstanceSecurityAspect"
factory-method="aspectOf">
<property name="securityInterceptor" ref="aspectJSecurityInterceptor"/>
</bean>]]>
</programlisting>
<para>That's it! Now you can create your beans from anywhere within your application, using
whatever means you think fit (eg <literal>new Person();</literal>) and they will have the
security interceptor applied.</para>
</section>
</chapter>