SEC-25: Rolled back addition of EJB integration docbook to ref manual.
This commit is contained in:
parent
934e59a562
commit
f0c15f5b1a
|
@ -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">
|
||||
|
|
Loading…
Reference in New Issue