Thursday, July 14, 2011

Best Practices: Cross-Context Dispatching and Session Handling

It’s been quite some time since I blogged. Thought of blogging this topic as recently we had faced a similar kind of problem that was faced earlier in another project. Just before going on to the problem and solution, let us first understand few basics and then move forward.

Understanding Session Tracking and JSESSIONID:

Basically a web container can use several methods to associate a session with a user, all of which involve passing an identifier between the client and the server. The identifier can be maintained on the client as a cookie, or the web component can include the identifier in every URL that is returned to the client.

JSESSIONID is a unique identifier of the HTTP session generated by the web container, stored within the cookie and is also the default cookie name. JSESSIONID cookie is created/sent when session is created. If cookies are turned off, the identifier is encoded in the URL link and if the cookies are turned on, the URL is simply empty and the identifier is available in the cookie itself.

Another misconception is that session gets created during first request which is not actually the case and totally up to the code to determine on when it should be created. To better understand this behavior,

  • In Java Servlet, new session is created when your code calls request.getSession() or request.getSession(true) for the first time. If you just want to get session if exists and do not want to create it if it doesn't exists, use request.getSession(false) that will return you a session if exists or null if it doesn’t. In this case, new session is not created and JSESSIONID cookie is not sent to the client browser that also means the session is not necessarily created on first request.

  • In JSP, new session is created whenever a call is made to the JSP page for the first time and uses the already available session for other subsequent requests. If we need to turn off this feature in a particular JSP page, use session=”false” page directive in which case session variable is not available on that JSP page at all.


Problem Description:

In case there are two or more different web application contexts accessed by the same user from the same domain, each request from the same user will generate cookie with its own session id that will get overridden and loose the session it had already set up.

By default all popular browser has the parent (main) window and the child (pop-up) window sharing the same cookie whenever the session is tracked using cookies. Assume the scenario where there are two different web applications deployed under the same server domain and each are accessed via their own context roots, the parent window accesses the first application and child window with the second application. In this case, as parent window and child window accesses two different applications from the same domain, session information gets overridden because the cookie name is same and the new Identifier (JSESSIONID) named cookie gets overridden due to which parent window looses it session data.

For instance, we had two different applications (say for example /app1 and /app2) running under the same domain (say for example http://www.samedomain.com/), parent window accesses the first application (http://www.samedomain.com/app1/) and through it, opens a child window with the second application (http://www.samedomain.com/app2) . When the parent window opens, it creates a cookie named with JSESSIONID and stores client session related information. As soon as the child window is opened, the existing session gets overridden by the app2 session as cookie names are same resulting in loss of session data in parent screen. Post this, whenever user navigates within parent screen for anything session specific will not fetch them the required data.

Solution Description:

Any of the below two approaches can be employed to prevent the session override problem

  1. Changing the cookie name from default value.

  2. Changing the cookie path (in case certain application server doesn’t allow to change the cookie name, we can create the same JSESSIONID named cookie into two different paths thus a work around way to prevent the override issue)


As each web container implementation differs even though they follow the same specification, above approaches can be employed using their proprietary configurations. Below are two different examples through which the above problem can be solved.

Illustration by Examples:

In Weblogic Application Server, changing the cookie name from default value. Suppose we have two applications deployed on Weblogic Application server, we can change the cookie name from its default JSESSIONID named cookie. This way, we can create application-specific cookies to avoid cookie override that in turn avoids the HTTP session override issue. Modify the weblogic.xml configuration specific to each application as below

<session-descriptor>
<session-param>
<param-name>CookieName</param-name>
<param-value>App1Cookie</param-value>
</session-param>
</session-descriptor>

By changing the cookie name, we ensure two different cookies created for each applications, thus ensuring that app1 and app2 sessions doesn't get overridden.

In Tomcat Web Server or JBoss Application server, changing the cookie path. We have the property named emptySessionPath used by the Apache connector’s configuration that states whether all cookie should be stored in the root folder “/” or not (otherwise) . This way, we can have cookies placed in two different location to avoid cookie override that in turn avoids HTTP session override issue. If emptySessionPath is enabled and set as “true” in Tomcat or JBoss, the JSESSIONID cookie is written to the root "/" path. If emptySessionPath is set to “false”, there are multiple cookies in the browser, one for each web app (none at the root), so different web apps are not re-writing each other's cookie. Modify the server.xml configuration specific to each application as below


<Connector port="8080" address="${jboss.bind.address}"maxThreads="5" maxHttpHeaderSize="8192"
emptySessionPath="false" protocol="HTTP/1.1" enableLookups="false" redirectPort="8443"
acceptCount="100" connectionTimeout="20000" disableUploadTimeout="true" />
<Connector port="8009" address="${jboss.bind.address}" protocol="AJP/1.3"
maxThreads="200" emptySessionPath="false" enableLookups="false" redirectPort="8443" />

By changing the emptySessionPath to "false", we ensure that the session cookies of app1 gets created at “/app1” instead of the default path of “/”, thus ensuring that app1 and app2 sessions doesn't get overridden.

1 comment:

  1. Hi, I have a requirement to NOT invalidate the session created in parent App as long as the session remains active in child App. To achieve this, I tried to set sessionID in the sendRedirect(...). However, the child App is always creating a new session. Any suggestions?

    ReplyDelete