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
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><intercept-methods></literal> or <literal><protect-point></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) |
|
&& 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"); |
|
} |
|
}</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>
|
|
|