Thursday 6 August 2015

Tomcat session mix-up hell (aka, RTFM)

Weirdness!

Recently I encountered a very strange issue where I would be logged out of an application in one tab if I opened a different instance of the same application (running on a different port but on the same machine) on another tab.

For clarity, this was my environment:
  • localhost
    • http://localhost:7224 → Application A1 on Tomcat T1 running with Java J1
    • http://localhost:8080 → Application A2 on Tomcat T2 running with Java J2

And what happened was this:
  1. Open A1 in Tab1
  2. Open A2 in Tab2
  3. Go to Tab1 and login to A1
  4. Go to Tab2 and refresh
  5. Go to Tab1 and refresh
  6. I am logged out from Tab1

WHAT?! But... how?

I am running two different instances on two different Tomcat containers using two different Javas?! Is there a leak somewhere? Unless... the problem is with the client. No. It couldn't be... could it?
I tried on other devices, other OSs, and other browsers... same thing. Ok, this must be something the server is sending back.

How I cursed at my computer.

Overnight I kept thinking about this and I realised I had this problem in my previous company. It wasn't the same but it was slightly similar but I remembered it had something to do with cookies.
Cookies are domain-specific (I was using localhost for both), this means they wouldn't care about ports. This was a good clue

The next morning I checked my StackOverflow question and Emmanuel Rosa had the courtesy of reminding my that Grails (well, the container) uses cookies to store session IDs.

RIGHT!

With Chrome, if you open Developer Tools → Resources Tab → Cookies you should see this:


According to the Tomcat 8 documentation there's an attribute called sessionCookieName which could be used to solve this.

So, how to fix it?

To address this issue, you'd have to make both apps stop competing for the JSESSIONID name. For Tomcat 8, if you look in {tomcat}/conf/context.xml the <Context> node is probably empty. This makes the session cookie name default to SESSIONID. The solution is to explicitly set sessionCookieName. After you do that change you should see something like below: <?xml version='1.0' encoding='utf-8'?> <Context sessionCookieName="APPNAMESESSIONID8080"> <WatchedResource>WEB-INF/web.xml>/WatchedResource> <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource> </Context> And you'd make a similar change for the other application: <?xml version='1.0' encoding='utf-8'?> <Context sessionCookieName="APPNAMESESSIONID7224"> <WatchedResource>WEB-INF/web.xml>/WatchedResource> <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource> </Context> I used DASHBOARDSESSIONID<portname> (as you can see in the screenshot below)
If you have another look at your developer tools, you should see that the issue is now gone (you may see the left-over JSESSIONID but that is ok. Your application will ignore it).

No comments:

Post a Comment