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
