|
@@ -4485,376 +4485,6 @@ $CATALINA_HOME/bin/startup.sh</programlisting></para>
|
|
|
<para>Finally, restart Tomcat.</para>
|
|
|
</sect1>
|
|
|
</chapter>
|
|
|
-
|
|
|
- <chapter>
|
|
|
- <title>Context propagation support for EJBs</title>
|
|
|
-
|
|
|
- <section>
|
|
|
- <title>Rationale</title>
|
|
|
-
|
|
|
- <para>Spring Security does provide transparent propagation of security
|
|
|
- context information in specific remoting scenarios. That means that
|
|
|
- the security context of the invoker is passed along with each method
|
|
|
- invocation to the server. There the context is being reestablished so
|
|
|
- that a service method can take place in the security context of the
|
|
|
- invoker. There is out-of-the-box support for RMI or Spring's own
|
|
|
- HttpInvoker protocol. Now many applications around are based on EJB
|
|
|
- remoting because of requirements or policy, which are precluded from
|
|
|
- that benefit.</para>
|
|
|
-
|
|
|
- <para>If you have an EJB application you have two options for
|
|
|
- integrating Spring Security:</para>
|
|
|
-
|
|
|
- <itemizedlist>
|
|
|
- <listitem>
|
|
|
- <para>Use a container adapter for integrating with that
|
|
|
- application server's proprietary security mechanism (Spring
|
|
|
- Security provides some ready usable adapters for use in legacy
|
|
|
- scenarios)</para>
|
|
|
- </listitem>
|
|
|
-
|
|
|
- <listitem>
|
|
|
- <para>Create wrappers on the client side (and on the server side
|
|
|
- when using POJO delegation) to propagate the security
|
|
|
- context</para>
|
|
|
- </listitem>
|
|
|
- </itemizedlist>
|
|
|
-
|
|
|
- <para>Both approaches have the benefit that the implementation of your
|
|
|
- service, as well as its clients, are agnostic to remoting and security
|
|
|
- context propagation taking place. The drawback of the first approach
|
|
|
- is, that you have to reimplement parts of your security infrastructure
|
|
|
- when switching the container (or maybe upgrading it, as sometimes the
|
|
|
- security strategy changes over time). That issue does not arise in the
|
|
|
- second approach, but the problem here is the implementation overhead
|
|
|
- of creating according wrappers to hide the context propagation.</para>
|
|
|
-
|
|
|
- <para>The following chapters describe the infrastructure classes which
|
|
|
- wrap the context propagation and abstract it away from both client
|
|
|
- usage and service implementation.</para>
|
|
|
- </section>
|
|
|
-
|
|
|
- <section>
|
|
|
- <title>How it works</title>
|
|
|
-
|
|
|
- <para>See figure 1 which describes the recommended POJO delegation
|
|
|
- model, where an EJB session bean only serves as remoting wrapper. The
|
|
|
- actual service implementation resides inside a POJO that implements
|
|
|
- the given business interface. The EJB implementation does nothing more
|
|
|
- than just delegating invocations of service operations to the POJO.
|
|
|
- Using Spring's support classes for wiring the POJO to the EJB is
|
|
|
- simple. Spring also allows wiring the service interface to the client
|
|
|
- by transparently wrapping the remote interface.</para>
|
|
|
-
|
|
|
- <para><figure>
|
|
|
- <title>Figure 1: Using EJB as remoting wrapper</title>
|
|
|
-
|
|
|
- <mediaobject>
|
|
|
- <imageobject>
|
|
|
- <imagedata fileref="images/ejb_pojo_delegation.gif" />
|
|
|
- </imageobject>
|
|
|
- </mediaobject>
|
|
|
- </figure></para>
|
|
|
-
|
|
|
- <para>This concept is now slightly enhanced by the context propagation
|
|
|
- module. As it is not possible to intercept the invocation of a remote
|
|
|
- interface in a portable manner, we have to extend the remote interface
|
|
|
- methods to include an additional parameter that holdes the
|
|
|
- SecurityContext we wish to propagate. In consequence we also have to
|
|
|
- modify the method implementations in the EJB implementation class to
|
|
|
- take that additional argument. This is depicted in figure 2. Note
|
|
|
- however, that the client still works with the plain business interface
|
|
|
- we had before and that the actual service implementation class is
|
|
|
- still the same.</para>
|
|
|
-
|
|
|
- <para><figure>
|
|
|
- <title>Figure 2: Using EJB as enhanced remoting wrapper</title>
|
|
|
-
|
|
|
- <mediaobject>
|
|
|
- <imageobject>
|
|
|
- <imagedata fileref="images/extended_ejb_pojo_delegation.gif" />
|
|
|
- </imageobject>
|
|
|
- </mediaobject>
|
|
|
- </figure></para>
|
|
|
-
|
|
|
- <para>Now how does this work? On the client side a proxy translates
|
|
|
- invocations from the business interface (Service) to invocations of
|
|
|
- the extended business interface (XService) which is actually exposed
|
|
|
- by the remote interface. The current security context is extracted and
|
|
|
- passed into the additionally provided method parameter.</para>
|
|
|
-
|
|
|
- <para>On the server side the EJB implementation refers to a delegate
|
|
|
- which also exposes the extended service interface (XService). Behind
|
|
|
- that service interface hides a proxy which extracts the passed-in
|
|
|
- SecurityContext and establishes it in the current thread. Then it
|
|
|
- delegates the invocation to the actual delegate class (ServiceImpl),
|
|
|
- translating the method invocation as the target does not know about
|
|
|
- the SecurityContext parameter. The invocation chain is exemplified in
|
|
|
- figure 3.</para>
|
|
|
-
|
|
|
- <para><figure>
|
|
|
- <title>Figure 3: Invocation chain</title>
|
|
|
-
|
|
|
- <mediaobject>
|
|
|
- <imageobject>
|
|
|
- <imagedata fileref="images/invocation_chain.gif" />
|
|
|
- </imageobject>
|
|
|
- </mediaobject>
|
|
|
- </figure>The yellow colored elements indicate instances exposing the
|
|
|
- extended business interface while the green colored elements indicate
|
|
|
- instances exposing the real business interface.</para>
|
|
|
- </section>
|
|
|
-
|
|
|
- <section>
|
|
|
- <title>How to use it</title>
|
|
|
-
|
|
|
- <para>The following subsections show how to use the provided
|
|
|
- infrastructure classes and how to enable your code to use them.</para>
|
|
|
-
|
|
|
- <section>
|
|
|
- <title>The building blocks</title>
|
|
|
-
|
|
|
- <section>
|
|
|
- <title>The business interface</title>
|
|
|
-
|
|
|
- <para><programlisting format="linespecific">public interface Service {
|
|
|
-
|
|
|
- Result operation(Parameter param);
|
|
|
- }</programlisting>How the business interface looks like depends just on,
|
|
|
- well, your business requirements. Nothing special about it.</para>
|
|
|
- </section>
|
|
|
-
|
|
|
- <section>
|
|
|
- <title>The service implementation</title>
|
|
|
-
|
|
|
- <para><programlisting>public class ServiceImpl implements Service {
|
|
|
-
|
|
|
- public Result operation(Parameter param) {
|
|
|
- ...
|
|
|
- }
|
|
|
- }</programlisting>The service implementation just implements the business
|
|
|
- interface, nothing more.</para>
|
|
|
- </section>
|
|
|
-
|
|
|
- <section>
|
|
|
- <title>The extended business interface and the remote
|
|
|
- interface</title>
|
|
|
-
|
|
|
- <para><programlisting>// Extended business interface
|
|
|
- public interface XService {
|
|
|
-
|
|
|
- public Result operation(SecurityContext securityCtx, Parameter param) throws SecurityServiceException, RemoteException;
|
|
|
- } </programlisting></para>
|
|
|
-
|
|
|
- <para><programlisting>// Remote interface
|
|
|
- public interface ServiceRemote extends XService, EJBObject {}</programlisting>The
|
|
|
- extended business interface introduces an additional parameter for
|
|
|
- each method (which is by convention the first parameter). Besides
|
|
|
- that augmentation of the parameter list we have to consider that
|
|
|
- this interface is being used in an EJB remoting scenario, so we
|
|
|
- specify a "throws RemoteException" for each method. This is not
|
|
|
- strictly necessary but it allows us to greatly simplify the
|
|
|
- definition of the actual remote interface as could be seen in the
|
|
|
- second listing.</para>
|
|
|
-
|
|
|
- <para>In addition to the RemoteException, each method also should
|
|
|
- declare throwing a
|
|
|
- org.springframework.security.ejb.server.SecurityServiceException.
|
|
|
- This is because of the EJB spec: If an EJB method throws an
|
|
|
- unchecked exception (all Spring Security exceptions are unchecked)
|
|
|
- that exception will be wrapped into a RemoteException and the bean
|
|
|
- instance will be dropped from the container. As this is unwanted
|
|
|
- and negatively impacts performance we declare the
|
|
|
- SecurityServiceException to be thrown. So any security exceptions
|
|
|
- will be wrapped into a SecurityServiceException to be passed to
|
|
|
- the client. Note that everything still works when that declaration
|
|
|
- is omitted, but consider the negative consequences for the EJB in
|
|
|
- question.</para>
|
|
|
- </section>
|
|
|
-
|
|
|
- <section>
|
|
|
- <title>The EJB implementation</title>
|
|
|
-
|
|
|
- <para><programlisting>public class ServiceBean extends AbstractStatelessSessionBean implements XService {
|
|
|
-
|
|
|
- private static final long serialVersionUID = 1L;
|
|
|
-
|
|
|
- /**
|
|
|
- * Delegate bean name.
|
|
|
- */
|
|
|
- private static final String DELEGATE_BEAN_NAME = "xService";
|
|
|
-
|
|
|
- /**
|
|
|
- * The delegate.
|
|
|
- */
|
|
|
- private XService delegate;
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * @see org.springframework.ejb.support.AbstractStatelessSessionBean#onEjbCreate()
|
|
|
- */
|
|
|
- protected void onEjbCreate() throws CreateException {
|
|
|
- this.delegate = (XService) getBeanFactory().getBean(DELEGATE_BEAN_NAME, XService.class);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * @see XService#operation(SecurityContext, Parameter)
|
|
|
- */
|
|
|
- public Result operation(SecurityContext securityCtx, Parameter param) throws SecurityServiceException, RemoteException {
|
|
|
- return this.delegate.operation(ctx, name);
|
|
|
- }
|
|
|
- }</programlisting></para>
|
|
|
-
|
|
|
- <para>It is recommended to use the convenience
|
|
|
- AbstractStatelessSessionBean base class provided by the Spring
|
|
|
- Framework. Implementation is then reduced to implementing the
|
|
|
- onEjbCreate()-callback method to retrieve the delegate bean and to
|
|
|
- implement the methods to do the delegation.</para>
|
|
|
- </section>
|
|
|
- </section>
|
|
|
-
|
|
|
- <section>
|
|
|
- <title>Wiring the client-side</title>
|
|
|
-
|
|
|
- <para><programlisting><?xml version="1.0" encoding="UTF-8"?>
|
|
|
- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
|
|
|
-
|
|
|
- <beans>
|
|
|
-
|
|
|
- <bean id="client" class="client.Client">
|
|
|
- <property name="service" ref="service"/>
|
|
|
- </bean>
|
|
|
-
|
|
|
- <bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate">
|
|
|
- <property name="environment">
|
|
|
- <value>
|
|
|
- // ...
|
|
|
- </value>
|
|
|
- </property>
|
|
|
- </bean>
|
|
|
-
|
|
|
- <bean id="service" class="org.springframework.security.ejb.client.SecurityContextInjectingRemoteSlsbProxyFactoryBean">
|
|
|
-
|
|
|
- <property name="businessInterface" value="server.Service"/>
|
|
|
-
|
|
|
- <property name="slsbBusinessInterface" value="server.XService"/>
|
|
|
-
|
|
|
- <property name="jndiTemplate" ref="jndiTemplate"/>
|
|
|
-
|
|
|
- <property name="jndiName" value="ejb/Service"/>
|
|
|
-
|
|
|
- <property name="extraArgumentPosition" value="0"/>
|
|
|
-
|
|
|
- <property name="methodRegexpPatterns">
|
|
|
- <list>
|
|
|
- <value>.*</value>
|
|
|
- </list>
|
|
|
- </property>
|
|
|
-
|
|
|
- </bean>
|
|
|
- </beans></programlisting>The above listing shows how the the service
|
|
|
- is being wired to the client. Instead of using a
|
|
|
- SimpleRemoteStatelessSessionProxyFactoryBean we use a
|
|
|
- SecurityContextInjectingRemoteSlsbProxyFactoryBean which provides
|
|
|
- the same functionality but is enhanced for hiding context
|
|
|
- propagation.</para>
|
|
|
-
|
|
|
- <para>The specified "businessInterface" property designates the
|
|
|
- actual business interface while the property "slsbBusinessInterface"
|
|
|
- specifies the extended business interface (it conforms to the
|
|
|
- SimpleRemoteStatelessSessionProxyFactoryBean#businessInterface
|
|
|
- property).</para>
|
|
|
-
|
|
|
- <para>The "extraArgumentPosition" and "methodRegexpPatterns"
|
|
|
- properties are optional. The former specifies the index of the
|
|
|
- parameter to insert. The default is 0 which means that the
|
|
|
- SecurityContext parameter will be the first one in the parameter
|
|
|
- list. The latter parameter specifies which methods to enhance by an
|
|
|
- additional SecurityContext parameter. By default all exposed methods
|
|
|
- are enhanced.</para>
|
|
|
-
|
|
|
- <para>Most other properties correspond to those in
|
|
|
- SimpleRemoteStatelessSessionProxyFactoryBean. Please refer to the
|
|
|
- API documentation for more details.</para>
|
|
|
- </section>
|
|
|
-
|
|
|
- <section>
|
|
|
- <title>Wiring the server-side</title>
|
|
|
-
|
|
|
- <para><programlisting><?xml version="1.0" encoding="UTF-8"?>
|
|
|
- <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
|
|
|
-
|
|
|
- <beans>
|
|
|
-
|
|
|
- <!-- Proxy for extracting secure context information -->
|
|
|
- <bean id="xService" class="org.springframework.security.ejb.server.support.SecurityContextExtractingProxyFactoryBean">
|
|
|
-
|
|
|
- <property name="businessInterface" value="server.XService"/>
|
|
|
-
|
|
|
- <property name="interceptorNames">
|
|
|
- <list>
|
|
|
- <value>serviceSecurityInterceptor</value>
|
|
|
- </list>
|
|
|
- </property>
|
|
|
-
|
|
|
- <property name="target" ref="serviceTarget"/>
|
|
|
-
|
|
|
- <property name="extraArgumentPosition" value="0"/>
|
|
|
-
|
|
|
- <property name="methodRegexpPatterns">
|
|
|
- <list>
|
|
|
- <value>.*</value>
|
|
|
- </list>
|
|
|
- </property>
|
|
|
- </bean>
|
|
|
-
|
|
|
- <!-- Security interceptor -->
|
|
|
- <bean id="helloServiceSecurityInterceptor" class="org.springframework.security.ejb.server.support.TranslatingMethodSecurityInterceptor">
|
|
|
- <property name="validateConfigAttributes" value="true"/>
|
|
|
- <property name="authenticationManager" ref="authenticationManager"/>
|
|
|
- <property name="accessDecisionManager" ref="accessDecisionManager"/>
|
|
|
- <property name="runAsManager" ref="runAsManager"/>
|
|
|
-
|
|
|
- <property name="objectDefinitionSource">
|
|
|
- <value>server.Service.*=ROLE_USER</value>
|
|
|
- </property>
|
|
|
- </bean>
|
|
|
-
|
|
|
- <!-- Service implementation -->
|
|
|
- <bean id="serviceTarget" class="server.ServiceImpl">
|
|
|
- </bean>
|
|
|
-
|
|
|
- </beans></programlisting></para>
|
|
|
-
|
|
|
- <para>The definition of the EJB's delegate bean (xService) is
|
|
|
- actually a SecurityContextExtractingProxyFactoryBean which creates a
|
|
|
- proxy that takes care of extracting the SecurityContext,
|
|
|
- establishing it, and delegating to the target bean
|
|
|
- (serviceTarget).</para>
|
|
|
-
|
|
|
- <para>The "businessInterface" property is again the extended
|
|
|
- business interface exposed by proxies created by the factory bean.
|
|
|
- The "target" refers to the actual target bean, while the
|
|
|
- "interceptorNames" property refers to a list of interceptor names
|
|
|
- which have to be defined in the application context.</para>
|
|
|
-
|
|
|
- <para>Note that the security interceptor is of type
|
|
|
- "TranslatingMethodSecurityInterceptor". It is a subclass of
|
|
|
- org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor
|
|
|
- and additionaly wraps all security exceptions into a
|
|
|
- SecurityServiceException, if possible. For its parameterization
|
|
|
- refer to the documentation of MethodSecurityInterceptor.</para>
|
|
|
-
|
|
|
- <para>The "extraArgumentPosition" and "methodRegexpPatterns"
|
|
|
- properties are again optional, specifying the position of the
|
|
|
- additional SecurityContext parameter and which methods will be
|
|
|
- augmented by it. It is important that both properties are specified
|
|
|
- the same on client and server. As recommendation just omit
|
|
|
- specifying these properties and stick with the default
|
|
|
- values.</para>
|
|
|
- </section>
|
|
|
- </section>
|
|
|
- </chapter>
|
|
|
</part>
|
|
|
|
|
|
<part id="authorization">
|