views:

3878

answers:

6

By default tomcat will create a session cookie for the current domain.

If you are on www.example.com, your cookie will be created for www.example.com (will only work on www.example.com). Whereas for example.com it will be created for .example.com (desired behaviour, will work on any subdomain of example.com as well as example.com itself).

I've seen a few Tomcat valves which seem to intercept the creation of session cookies and create a replacement cookie with the correct .example.com domain, however none of them seem to work flawlessly and they all appear to leave the existing cookie and just create a new one. This means that two JSESSIONID cookies are being sent with each request.

I was wondering if anybody has a definitive solution to this problem.

+1  A: 

I've run into this at $DAYJOB. In my case I wanted to implement SSL signon then redirect to a non SSL page. The core problem in tomcat is the method (from memory) SessionManager.configureSessionCookie which hard codes all the variables you would like to get access to.

I came up with a few ideas, including a particularly egregious hack using mod_headers in apache to rewrite the cookie based on regex substitution.

The definative way to solve this would be to submit a patch to the tomcat developers that adds configurable parameters to the SessionManager class.

Dave Cheney
A: 

As a session (and its Id) is basically considered of value only for the issueing application, you may rather look for setting an additional cookie. Have a look at Tomcats SingleSignOnValve, providing the extra-Cookie JSESSIONIDSSO (note the ...SSO) for the server path "/" instead of "/applicationName" (as JSESSIONID cookies are usually set).

With such a Valve you may implement any interprocess communication you need in order to synchronize any state between different servers, virtual hosts or webapps on any number of tomcats/webservers/whatever.

Another reason why you cannot use tomcats session cookie for your own purposes is, that multiple webapps on the same host have different session ids. E.g. there are different cookies for "/webapp1" and "/webapp2". If you provide "/webapp1"'s cookie to "/webapp2", this wouldn't find the session you referenced, invalidate your session+cookie and set its own new one. You'd have to rewrite all of tomcats session handling to accept external session id values (bad idea securitywise) or to share a certain state among applications.

Session handling should be considered the containers (tomcats) business. Whatever else you need you should add without interfering with what the container believes is necessary to do.

Olaf
A: 

the solution pointed out at nabble works for me. took me nearly a day to find a working solution. i just had to replace the debug messages with system.out to make it work in tomcat 5.5 instead of 6

Andreas Petersson
A: 

The valve techniques do not seem to be 100% perfect. If you dare to modify Tomcat itself:

catalina.jar contains the following class: org.apache.catalina.connector.Request

The Request has a method: configureSessionCookie(Cookie cookie)

For our environment it was best to just hardcode it, but you could do more fancy logic:

cookie.setDomain(".xyz.com");

Seems to work perfectly. Would be nice if this was configurable in tomcat.

A: 

I have just gone through all of this looking for a simple solution. I started looking at it from the tomcat perspective first.

Tomcat does not give direct access to configuring the domain cookie for the session, and I definitely did not want to custom patch tomcat to fix that problem as shown in some other posts.

Valves in tomcat also seems to be a problem solution due to the limitations on accessing headers & cookies built into the Servlet specification. They also fail completely if the http response is commited before it gets passed to your valve.

Since we proxy our requests through Apache, I then moved onto how to use apache to fix the problem instead.

I first tried the mod_proxy directive ProxyPassReverseCookieDomain, but it does not work for JSESSIONID cookies because tomcat does not set the domain attribute and ProxyPassReverseCookieDomain cannot work without some sort of domain being part of the cookie.

I also came across a hack using ProxyPassReverseCookiePath where they were rewriting the path to add a domain attribute to the cookie, but that felt way to messy for a production site.

I finally got it to work by rewriting the response headers using the mod_headers module in apache as mentioned by Dave above.

I have added the following line inside the virtual host definition:

Header edit Set-Cookie "(JSESSIONID\s?=[^;,]+?)((?:;\s?(?:(?i)Comment|Max-Age|Path|Version|Secure)[^;,]*?)*)(;\s?(?:(?i)Domain\s?=)[^;,]+?)?((?:;\s?(?:(?i)Comment|Max-Age|Path|Version|Secure)[^;,]*?)*)(,|$)" "$1$2; Domain=.example.com$4$5"

The above should all be a single line in the config. It will replace any JSESSIONID cookies domain attribute with ".example.com". If a JSESSIONID cookie does not contain a domain attribute, then the pattern will add one with a value of ".example.com". As a bonus, this solution does not suffer from the double JSESSION cookies problem of the valves.

The pattern should work with multiple cookies in the Set-Cookie header without affecting the other cookies in the header. It should also be modifiable to work with other cookies by changing JSESSIONID in the first part of the pattern to what ever cookie name you desire.

I am not reg-ex power user, so I am sure there are a couple of optimisations that could be made to the pattern, but it seems to be working for us so far.

I will update this post if I find any bugs with the pattern. Hopefully this will stop a few of you from having to go through the last couple of days worth of frustrations as I did.

Jason Butler
+2  A: 

This is apparently supported via a configuration setting in 6.0.27 and onwards:

Configuration is done by editing META-INF/context.xml

<Context sessionCookiePath="/something" sessionCookieDomain=".domain.tld" />

https://issues.apache.org/bugzilla/show_bug.cgi?id=48379

mkvalsvik