328 lines
16 KiB
XML
328 lines
16 KiB
XML
<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 MethodSecurityIterceptor 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.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> ]]>
|
|
</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.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>]]> </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>objectDefinitionSource</literal>, as the
|
|
<interfacename>ObjectDefinitionSource</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>
|
|
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");
|
|
}
|
|
}</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>
|
|
|
|
<section xml:id="filter-invocation-authorization">
|
|
<info><title>FilterInvocation Security Interceptor</title></info>
|
|
|
|
<para>To secure <classname>FilterInvocation</classname>s, developers need
|
|
to add a <classname>FilterSecurityInterceptor</classname> to their filter chain.
|
|
A typical configuration example is provided below:</para>
|
|
|
|
<para>In the application context you will need to configure three
|
|
beans:</para>
|
|
|
|
<programlisting>
|
|
<![CDATA[
|
|
<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>]]> </programlisting>
|
|
|
|
<para>The <classname>ExceptionTranslationFilter</classname> 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
|
|
<exceptionname>AuthenticationException</exceptionname> is detected,
|
|
the filter will call the AuthenticationEntryPoint to commence the
|
|
authentication process (e.g. a user login).</para>
|
|
|
|
<para>The <interfacename>AuthenticationEntryPoint</interfacename> 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:
|
|
<classname>AuthenticationProcessingFilterEntryPoint</classname> for
|
|
commencing a form-based authentication,
|
|
<literal>BasicProcessingFilterEntryPoint</literal> for commencing a
|
|
HTTP Basic authentication process, and
|
|
<literal>CasProcessingFilterEntryPoint</literal> for commencing a
|
|
JA-SIG Central Authentication Service (CAS) login. The
|
|
<classname>AuthenticationProcessingFilterEntryPoint</classname> and
|
|
<literal>CasProcessingFilterEntryPoint</literal> have optional
|
|
properties related to forcing the use of HTTPS, so please refer to the
|
|
JavaDocs if you require this.</para>
|
|
|
|
<para><classname>FilterSecurityInterceptor</classname> is responsible for
|
|
handling the security of HTTP resources. Like any other security
|
|
interceptor, it requires a reference to an
|
|
<interfacename>AuthenticationManager</interfacename> and an
|
|
<interfacename>AccessDecisionManager</interfacename>, which are both discussed in
|
|
separate sections below. The
|
|
<classname>FilterSecurityInterceptor</classname> 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.</para>
|
|
|
|
<para>The <classname>FilterSecurityInterceptor</classname> can be
|
|
configured with configuration attributes in two ways. The first,
|
|
which is shown above, is using the <literal><filter-invocation-definition-source></literal>
|
|
namespace element. This is similar to the <literal><filter-chain-map></literal>
|
|
used to configure a <classname>FilterChainProxy</classname> but the <literal><intercept-url></literal>
|
|
child elements only use the <literal>pattern</literal> and <literal>access</literal> attributes.
|
|
The second is by writing your own
|
|
<interfacename>ObjectDefinitionSource</interfacename>, although this is beyond the
|
|
scope of this document. Irrespective of the approach used, the
|
|
<interfacename>ObjectDefinitionSource</interfacename> is responsible for returning
|
|
a <literal>List<ConfigAttribute></literal> containing
|
|
all of the configuration attributes associated with a single secure
|
|
HTTP URL.</para>
|
|
|
|
<para>It should be noted that the
|
|
<literal>FilterSecurityInterceptor.setObjectDefinitionSource()</literal>
|
|
method actually expects an instance of
|
|
<interfacename>FilterInvocationDefinitionSource</interfacename>. This is a marker
|
|
interface which subclasses <interfacename>ObjectDefinitionSource</interfacename>.
|
|
It simply denotes the <interfacename>ObjectDefinitionSource</interfacename>
|
|
understands <classname>FilterInvocation</classname>s. In the interests of
|
|
simplicity we'll continue to refer to the
|
|
<interfacename>FilterInvocationDefinitionSource</interfacename> as an
|
|
<interfacename>ObjectDefinitionSource</interfacename>, as the distinction is of
|
|
little relevance to most users of the
|
|
<classname>FilterSecurityInterceptor</classname>.</para>
|
|
|
|
<para>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 <literal>SecurityConfig</literal> object. The
|
|
<literal>SecurityConfig</literal> object is discussed in the High
|
|
Level Design section. The <interfacename>ObjectDefinitionSource</interfacename>
|
|
created by the property editor,
|
|
<interfacename>FilterInvocationDefinitionSource</interfacename>, matches
|
|
configuration attributes against <literal>FilterInvocations</literal>
|
|
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 <literal>path-type</literal> 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:</para>
|
|
|
|
<programlisting><![CDATA[
|
|
<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>]]> </programlisting>
|
|
|
|
<para>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 <literal>/secure/super/</literal>
|
|
pattern appears higher than the less specific
|
|
<literal>/secure/</literal> pattern. If they were reversed, the
|
|
<literal>/secure/</literal> pattern would always match and the
|
|
<literal>/secure/super/</literal> pattern would never be
|
|
evaluated.</para>
|
|
|
|
<para>As with other security interceptors, the
|
|
<literal>validateConfigAttributes</literal> property is observed. When
|
|
set to <literal>true</literal> (the default), at startup time the
|
|
<classname>FilterSecurityInterceptor</classname> will evaluate if the
|
|
provided configuration attributes are valid. It does this by checking
|
|
each configuration attribute can be processed by either the
|
|
<interfacename>AccessDecisionManager</interfacename> or the
|
|
<literal>RunAsManager</literal>. If neither of these can process a
|
|
given configuration attribute, an exception is thrown.</para>
|
|
</section>
|
|
</chapter>
|