Can I SSO between multiple Wars in the same servlet with Stormpath and Apache Shiro?

It's possible to use Stormpath and Apache Shiro for SSO on two different WARs deployed to the same servlet (eg Tomcat). For instance, we have two Wars:

  • WarA is deployed to Tomcat
  • WarB is deployed to the same Tomcat

We want a user to be able to authenticate against http://localhost:8080/WarA/login and be automatically authenticated against http://localhost:80808/WarB/hello

Using the Servlet Plugin 

As of stormpath-shiro 0.7.0, this will work without any additional configuration when using one of the Stormpath-Shiro integrations (stormpath-shiro-servlet or stormpath-shiro-spring-boot-web-starter).
 
For example, a Maven war project just needs to contain the dependency:
 
<dependency>
    <groupId>com.stormpath.shiro</groupId>
    <artifactId>stormpath-shiro-servlet-plugin</artifactId>
    <version>0.7.0</version>
</dependency>
 
This will play nice with any Stormpath application using JWTs (not just Shiro). Further, they do NOT need to be running in the same Application Server.
 
NOT using the Servlet Plugin
 

To achieve this, both the WarA and warB applications need to 'point' at the same Apache Shiro session store and read the same session ID cookie.

Here's how you configure your app to make this work:

1) In both Applications (WarA and WarB), the shiro.ini file should look like this:

[main]
shiro.loginUrl = /login.jsp

#By default, the EhCacheManager uses a Shiro-specific ehcache.xml file. However, we need to customize the cache settings
cacheManager = org.apache.shiro.cache.ehcache.EhCacheManager
cacheManager.cacheManagerConfigFile = classpath:ehcache.xml

#Configure a CacheManager for all of Shiro's needs. This CacheManager instance will propagate down to the SessionDAO automatically
securityManager.cacheManager = $cacheManager

# Now integrate with Stormpath

stormpathClient = com.stormpath.shiro.client.ClientFactory
stormpathClient.apiKeyFileLocation = ***PATH***/.stormpath/apiKey.properties

stormpathRealm = com.stormpath.shiro.realm.ApplicationRealm
stormpathRealm.client = $stormpathClient

# The Stormpath App Rest URL:
stormpathRealm.applicationRestUrl = *** Stormpath App Rest URL Here ***

stormpathRealm.authenticationCachingEnabled = true
stormpathRealm.authorizationCachingEnabled = true
securityManager.realm = $stormpathRealm

#Enable a SessionDAO in a web-based application for custom session storage
sessionDAO = org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO
sessionManager = org.apache.shiro.web.session.mgt.DefaultWebSessionManager
sessionManager.sessionDAO = $sessionDAO

#Native session mode
securityManager.sessionMode = native

#Let's configure our cookie
cookie = org.apache.shiro.web.servlet.SimpleCookie
cookie.name = SSOcookie
cookie.path = /
cookie.domain = localhost
sessionManager.sessionIdCookie = $cookie

#Let's set the session manager after the cookie has been set, otherwise it gets overwritten
securityManager.sessionManager = $sessionManager

[urls]
# Your app-specific URLs here.

2) Add this ehcache.xml file to the resource directory of both applications:

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="ehcache.xsd" updateCheck="true"
         monitoring="autodetect" dynamicConfig="true">

    <diskStore path="java.io.tmpdir" />

    <cacheManagerPeerProviderFactory
            class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
            properties="peerDiscovery=automatic,
                        multicastGroupAddress=230.0.0.1,
                        multicastGroupPort=4446, timeToLive=1"
            propertySeparator="," />

    <cacheManagerPeerListenerFactory
            class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory" />

    <cache name="shiro-activeSessionCache" maxElementsInMemory="600"
           eternal="true" overflowToDisk="true" memoryStoreEvictionPolicy="LFU">
        <cacheEventListenerFactory
                class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
    </cache>

    <defaultCache maxElementsInMemory="100" eternal="true"
                  overflowToDisk="true" memoryStoreEvictionPolicy="LFU">
    </defaultCache>
</ehcache>

3) Ensure that you have the shiro-ehcache-<version>.jar file in your classpath

That's it for the configuration! Here are the steps to execute:

  1. Deploy both wars into your servlet container (e.g. Tomcat)
  2. Start your servlet container
  3. Open either Firefox or Safari (Chrome does not currently work)
  4. Open any page in WarA and login (e.g. http://localhost:8080/WarA/login)
  5. Go to any restricted page in the WarB app and you should not be prompted again for authentication

Keep in mind that SSO will only work if the login happens after both WARs have been deployed to the server. For example, let's suppose we have only deployed WarA and a user logs in. If we then deploy WarB, the user won't have a session for application B. Login needs to occur after both apps have been deployed in order for SSO to succeed.

Have more questions? Submit a request

Comments

0 comments

Please sign in to leave a comment.