Help

Built with Seam

You can find the full source code for this website in the Seam package in the directory /examples/wiki. It is licensed under the LGPL.

Tomcat loose session cookie when protocol changes from https to http, and you can see the trouble when you're trying to logout. The symptom is the famous NotLoggedInException. Here is the code that solves the problem.

package org.test;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Startup;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.annotations.web.Filter;

/**
 * One way to maintain the session in Tomcat, when the session cookie is getting
 * created in SSL mode is to trick the browser by creating the non-secure cookie,
 * when the secure cookie is getting created. To do that, we need to create an 
 * request wrapper
 */
@Startup
@Scope(ScopeType.APPLICATION)
@Name("org.test.httpsHttpTrickFilter")
@BypassInterceptors
@Filter(within="org.jboss.seam.web.ajax4jsfFilter")
public class HttpsHttpTrickFilter implements javax.servlet.Filter {

        public void destroy() {
                // do nothing
        }

        public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
                
                // create the requestWrapper in order to process the cookie
                SecureRequestWrapper requestWrapper = new SecureRequestWrapper((HttpServletRequest)request);
                requestWrapper.setResponse((HttpServletResponse)response);
                
                // continue
                chain.doFilter(requestWrapper, response);
        }

        public void init(FilterConfig filterConfig) throws ServletException {
                // do nothing
        }
        
}

and this request wrapper creates a unsecure cookie to resolve the issue.

package org.test;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * One way to maintain the session in Tomcat, when the session cookie is getting
 * created in SSL mode is to trick the browser by creating the non-secure cookie,
 * when the secure cookie is getting created. To do that, we need to create an 
 * request wrapper
 */
public class SecureRequestWrapper extends HttpServletRequestWrapper {

	private HttpServletResponse response = null;

	public SecureRequestWrapper(HttpServletRequest request) {
		super(request);
	}

	public void setResponse(HttpServletResponse response) {
		this.response = response;
	}

	public HttpSession getSession() {
		HttpSession session = super.getSession();
		processSessionCookie(session);
		return session;
	}
	
	public HttpSession getSession(boolean create) {
		HttpSession session = super.getSession(create);
		processSessionCookie(session);
		return session;
	}
	
	private void processSessionCookie(HttpSession session) {
		
		if (null == response || null == session) {
			return;
		}
		
		// cookieOverWritten - Flag to filter multiple "Set-Cookie" headers
		Object cookieOverWritten = getAttribute("COOKIE_OVERWRITTEN_FLAG");
		if (null == cookieOverWritten && isSecure() && isRequestedSessionIdFromCookie() && session.isNew()) {
			
			Cookie cookie = createCookie(session);
			
			// Adding an "Set-Cookie" header to the response
			response.addCookie(cookie); 
			
			// To avoid multiple "Set-Cookie" header
			setAttribute("COOKIE_OVERWRITTEN_FLAG", "true");
		}
	}

	/**
	 * Might have created the cookie in SSL protocol and tomcat will loose the session
	 * if there is change in protocol from HTTPS to HTTP. To avoid
	 * this, trick the browser using the HTTP and HTTPS session cookie.
	 * @param session
	 * 
	 * @return the cookie
	 */
	private Cookie createCookie(HttpSession session) {
		Cookie cookie = new Cookie("JSESSIONID", session.getId());
		cookie.setMaxAge(-1); // Life of the browser or timeout
		String contextPath = getContextPath();
		if ((contextPath != null) && (contextPath.length() > 0)) {
			cookie.setPath(contextPath);
		} 
		else {
			cookie.setPath("/");
		}
		return cookie;
	}


}
3 comments:
 
08. Jul 2008, 16:19 America/New_York | Link

There is a problem although the code of the filter looks ok... It doesnt work always the http session is fixed only 2 times in 5 tries smth doesnt work as it supposed to.

 
17. Jul 2008, 20:28 America/New_York | Link
Maximiliano Carrizo | demostenes1509.AT.gmail.com

Please, explain me more carefully what you mean. Thank you very much !!

 
29. Nov 2008, 02:48 America/New_York | Link

Hi ! Thanks Maximiliano, I was having this exact problem and your code did the trick ! I was just wondering, is this a Tomcat os Seam bug? I'm asking cause I didn't quite understood what was really the cause of the problem, if you could explain me with a little more detail it would be much appreciated ! Thanks !