Sharing session data between contexts in Tomcat

I have been looking at solutions for sharing session data between mutliple war files. I came across the following solution http://www.fwd.at/tomcat/sharing-session-data-howto.html

The basic idea of it is that if you have more than one war file, you can set a cookie using the sessionid of the first context that is used.

The cookie can be set using a path that will apply to all contexts/applications.

For example, if I have the following configuration for 3 applications

/myapp/app1
/myapp/app2
/myapp/app3

I can set a cookie as follows

/myapp sessionid.

The sessionid cookie will then be sent to any request with /myapp in the address. This allows the session id to then be used by any of the contexts.

The only problem with this approach is that it was written in 2003 and tested on Tomcat 4.

What are your opinions of this approach? Is there a better way of doing it?

Thanks


Solution 1:

That article is indeed heavily outdated.

On Tomcat 5.5 and 6.0 you can just set emptySessionPath attribute to true in the <Connector> element in /conf/server.xml.

<Connector ... emptySessionPath="true">

On Tomcat 7.0 this has changed because this is now configureable from the Servlet 3.0 API on. It's then on Tomcat's side configureable by setting sessionCookiePath to / in <Context> element in any responsible context.xml file.

<Context ... sessionCookiePath="/">

As said, there's a new Servlet 3.0 API which allows you to configure the session cookie through the standard API. You can do it either declaratively by adding the following to the web.xml:

<session-config>
    <cookie-config>
        <path>/</path>
    </cookie-config>
</session-config>

or programmatically by SessionCookieConfig which is available by ServletContext#getSessionCookieConfig().

getServletContext().getSessionCookieConfig().setPath("/");

You could do this in ServletContextListener#contextInitialized() or HttpServlet#init().

See also:

  • Tomcat 5.5 HTTP connector documentation
  • Tomcat 6.0 HTTP connector documentation - mentions potential security hole
  • Tomcat 7.0 context documentation

Solution 2:

To my knowledge there is no direct way to do this, you can however use a domain level cookie if these contexts share the same domain.

You can either put the data in the cookie (I don't recommend that).

Or put a secured session Id that you can use to access some form of storage (DB or distributed cache etc) to retrieve the data you need.

Solution 3:

If the amount of data is not astronomical and the data itself isn't changing too rapidly, you might want to consider using JNDI. This solution was designed exactly for what you are looking for.

You can have a look at official documentation or this post to tomcat-user mailing list for references & examples.

Solution 4:

For Tomcat 8 I use the following configuration to share a session across 2 webapps:

conf/context.xml

<Context sessionCookiePath="/">

    <Valve className="org.apache.catalina.valves.PersistentValve"/>
    <Manager className="org.apache.catalina.session.PersistentManager">
        <Store className="org.apache.catalina.session.FileStore" directory="${catalina.base}/temp/sessions"/>
    </Manager>

    ...

</Context>

I deploy the same simple webapp twice log.war and log2.war:

/log
/log2

I can now log-in to /log and have the user displayed in /log2, this does not work with the tomcat default configuration.

enter image description here

The session value is set and read:

HttpSession session=request.getSession();  
session.setAttribute("name",name);

HttpSession session=request.getSession(false);  
String name=(String)session.getAttribute("name");  

I used this project as example: https://www.javatpoint.com/servlet-http-session-login-and-logout-example

Most examples/solutions use a in-memory database which requires more setup work:

  • redis
  • hazelcast