SEC-25: Rolled back addition of EJB integration docbook to ref manual.

This commit is contained in:
Luke Taylor 2008-01-28 17:33:08 +00:00
parent 934e59a562
commit f0c15f5b1a
1 changed files with 0 additions and 370 deletions

View File

@ -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>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"&gt;
&lt;beans&gt;
&lt;bean id="client" class="client.Client"&gt;
&lt;property name="service" ref="service"/&gt;
&lt;/bean&gt;
&lt;bean id="jndiTemplate" class="org.springframework.jndi.JndiTemplate"&gt;
&lt;property name="environment"&gt;
&lt;value&gt;
// ...
&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;bean id="service" class="org.springframework.security.ejb.client.SecurityContextInjectingRemoteSlsbProxyFactoryBean"&gt;
&lt;property name="businessInterface" value="server.Service"/&gt;
&lt;property name="slsbBusinessInterface" value="server.XService"/&gt;
&lt;property name="jndiTemplate" ref="jndiTemplate"/&gt;
&lt;property name="jndiName" value="ejb/Service"/&gt;
&lt;property name="extraArgumentPosition" value="0"/&gt;
&lt;property name="methodRegexpPatterns"&gt;
&lt;list&gt;
&lt;value&gt;.*&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;/beans&gt;</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>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd"&gt;
&lt;beans&gt;
&lt;!-- Proxy for extracting secure context information --&gt;
&lt;bean id="xService" class="org.springframework.security.ejb.server.support.SecurityContextExtractingProxyFactoryBean"&gt;
&lt;property name="businessInterface" value="server.XService"/&gt;
&lt;property name="interceptorNames"&gt;
&lt;list&gt;
&lt;value&gt;serviceSecurityInterceptor&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;property name="target" ref="serviceTarget"/&gt;
&lt;property name="extraArgumentPosition" value="0"/&gt;
&lt;property name="methodRegexpPatterns"&gt;
&lt;list&gt;
&lt;value&gt;.*&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;!-- Security interceptor --&gt;
&lt;bean id="helloServiceSecurityInterceptor" class="org.springframework.security.ejb.server.support.TranslatingMethodSecurityInterceptor"&gt;
&lt;property name="validateConfigAttributes" value="true"/&gt;
&lt;property name="authenticationManager" ref="authenticationManager"/&gt;
&lt;property name="accessDecisionManager" ref="accessDecisionManager"/&gt;
&lt;property name="runAsManager" ref="runAsManager"/&gt;
&lt;property name="objectDefinitionSource"&gt;
&lt;value&gt;server.Service.*=ROLE_USER&lt;/value&gt;
&lt;/property&gt;
&lt;/bean&gt;
&lt;!-- Service implementation --&gt;
&lt;bean id="serviceTarget" class="server.ServiceImpl"&gt;
&lt;/bean&gt;
&lt;/beans&gt;</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">