Monday, January 17, 2011

I found out that in Tomcat 6, HttpServletRequest.getRequestURL() omits the ";jsessionid=[sessionid]", if present, while Tomcat 7 returns it. In either case, HttpServletResponse.encodeRedirectURL() adds it in or replaces it with the actual session id when the client has cookies disabled. However, what I needed was to have the ";jsessionid=[requested sessionid]", and not the actual session id, because I needed to reconstruct the URL that was actually sent for the redirect_uri parameter when obtaining an OAuth 2.0 access token.

What had happened was that when multiple hosts were added to the load balancer, clients with cookies disabled would get authentication failures. Since this was a new service in private beta, the immediate fix was to have a single host in the load balancer. I then would add a second host to the load balancer, do a quick test, then remove the second host from the load balancer, and then look at the logs to see what was going on. I had originally constructed the redirect_uri parameter using HttpServletResponse.encodeRedirectURL() on the results of HttpServletRequest.getRequestURL() and HttpServletRequest.getQueryString(). It worked fine with clients that had cookies enabled, because the session id wouldn't be in the URL, and the load balancer used cookies for host stickiness. However, for clients with disabled cookies, the load balancer would bounce the client between hosts for subsequent requests, and since sessions weren't really being shared between hosts, so when a client request gets sent to a different host, it gets a new session. (I did have a scheme to recover a very small set of essential session data through memcached, but I didn't think that saving redirect_uri in it was necessary, since it ought to be available when the client is retrieving that exact URL. I also should have a scheme to make sure the session ids from one host never collide with session ids from another host by prepending the hostname to the session id.)

After I figured out what was happening, I removed the HttpServletResponse.encodeRedirectURL() call in the construction of the redirect_uri parameter. It seemed fine to me, because I was using Tomcat 7. However, once it was running on other systems, there immediate failures for clients with disabled cookies. From the logs, I could tell that HttpServletRequest.getRequestURL() was omitting the ";jsessionid=[session id]", so I theorized that it was because of differences between Tomcat 6 and Tomcat 7, and quickly confirmed it by running Tomcat 6 myself.

I finally settled on an ugly hack, where if HttpServletRequest.isRequestedSessionIdFromURL() and if ":jsessionid=" were not in HttpServletRequest.getRequestURL(), I would add ";jsessionid=" + HttpServletRequest.getRequestedSessionId(), which would then work on Tomcat 6 and Tomcat 7.

No comments:

Post a Comment