123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154 |
- <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>MethodSecurityMetadataSource</interfacename> instance to obtain the
- configuration attributes that apply to a particular method invocation.
- <classname>MapBasedMethodSecurityMetadataSource</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 language="xml"><![CDATA[
- <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> ]]>
- </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 language="xml"><![CDATA[
- <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>]]> </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.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");
- }
- }
- }
- </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 language="xml"><![CDATA[
- <bean id="domainObjectInstanceSecurityAspect"
- class="security.samples.aspectj.DomainObjectInstanceSecurityAspect"
- factory-method="aspectOf">
- <property name="securityInterceptor" ref="bankManagerSecurity"/>
- </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>
|