Hi Les!

Thanks for your detailed answer.

> This is because once a Subject logs-in, Shiro will by default store
> the Subject's authentication state in the session, and so if the
> Session is accessible to both Shiro environments across JVMs, this
> will work as expected.  I call this 'Poor Man's Single Sign On' and
> I've used in a few applications now.  It works great.
>
> The key to this is to use the same SessionDAO in both JVM
> configurations.  Most people use Ehcache and/or Terracotta to ensure
> this works in a distributed environment.  See
> http://shiro.apache.org/session-management.html#SessionManagement-SessionStorage
> for more.
>
> This however does require server state to be maintained (e.g. in
> Hazelcast) and so therefore is not a stateless solution.

In this scenario, how does jvm2 query for an existing session - created by jvm1?
If we do not talk about web applications and do not already have
distributed servlet sessions - how does Shiro know which user is
authenticated in the current (ejb) request?

How is a returning user identified?

>> 3. If the only way is to enable sessionStorage - how does instance2
>> know which session ID to retrieve from the DAO?
>> Do I need to come up with my own solution (using EJB context or
>> something similar)?
>
> Based on what you've described thus far, I'm assuming you have an
> architecture similar to the following:
>
> Load Balancer --> Servlet Container --> Load Balancer --> EJB Server
> --> Data Store

It is more like:
Load Balancer --> Servlet Container --> EJB (clustered)
and
Message Queue (clustered) --> EJB (clustered)

Right now Servlet Container and EJBs are on the same machine, inside
one EAR - but we want to be able to split them out in the future.
There are 3 nodes in the cluster running this EAR.

> And you'd like the same Subject state to be available in the Servlet
> Container as well as the EJB Server for a single request down to the
> datastore and back.  Because you want a truly stateless architecture,
> you do not want shared sessions to be used, and this also implies that
> your clients (browser, app, whatever) will authenticate on every
> request since you don't want to store authentication state in a
> session.

Exactly.

> Shiro can actually support this use case very well assuming you are
> using the 1.2 SNAPSHOT since stateless app support is currently in SVN
> trunk.

We already use 1.2-SNAPSHOT because of a bug in 1.1.0 that prevents
the use of a JNDI Realm (JndiRealmFactory).
-> https://issues.apache.org/jira/browse/SHIRO-238

> 2.  Create some framework code to do the following:
>
> a.  When JVM 1 sends a remote invocation to JVM 2 (e.g. servlet
> container invokes an EJB proxy), you will want to attach the
> authentication state (subject.isAuthenticated() and the
> PrincipalCollection (subject.getPrincipals()) to the remote method
> invocation payload.
>
> b.  In the EJB Server, have an interceptor that intercepts all remote
> method invocations.  This interceptor will inspect the RMI payload,
> extract out the 'authenticated' boolean and the PrincipalCollection
> and create a Subject instance based on those two values.  For example:
>
> boolean authenticated = //get from RMI payload
> PrincipalCollection principals = //get from RMI payload
>
> Subject subject =
> Subject.Builder(ejbApplicationShiroSecurityManager).principals(principals).authenticated(authenticated).buildSubject();
>
> return subject.getExecute( new Callable() {
>    public Object call() throws Exception {
>        return ejbMethodInvocation.invoke(...);
>    }
> }
>
> This will create and bind the Subject state 'passed in' from the
> servlet container to the EJB server for further use.  Any object
> invoked during 'ejbMethodInvocation.invoke()' - the EJB, other EJBs,
> DAOs, etc, will all be able to call SecurityUtils.getSubject() just
> fine.
>
> Here is a working example that does this for Spring remoting, but
> would work identically for EJB remoting:
>
> http://svn.apache.org/repos/asf/shiro/trunk/support/spring/src/main/java/org/apache/shiro/spring/remoting/SecureRemoteInvocationExecutor.java
>
> The above steps (with the RMI interceptor) will work just fine, and it
> will still be stateless.

Thanks a lot, this is exactly what I was searching for.
Now I only need to find out how to intercept remote calls from the
servlet to the EJBs and attach some context information.
Not sure if CDI/EJB interceptors are able to handle this... from what
I know they come to play before calling the method on the server that
hosts the EJB.

I've found a post that tries to solve this problem - will investigate
this later.
-> http://home.java.net/node/707280


      -ps

Reply via email to