/******************************************************************************* * Copyright (c) 2008 Cambridge Semantics Incorporated. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package org.openanzo.combus.bayeux; import java.io.IOException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.cometd.server.AbstractBayeux; import org.cometd.server.JSONTransport; import org.openanzo.exceptions.AnzoRuntimeException; import org.openanzo.exceptions.ExceptionConstants; import org.openanzo.servlet.EncryptedTokenAuthenticator; /** * A specialization of the basic cometd JSONTransport. The only difference in behavior is that this transport will inspect the messages being sent in the * response to make sure that the response represents real data flowing to the client. If an HTTP response only contains the polling acknowledgment and nothing * else, then the transport will ensure that the timeout on the authentication isn't reset. * * Essentially this means that a cometd application will actually timeout even though the client keeps polling the server. Since we don't reset the timeout if a * response doesn't have any real data, then the client authentication will actually timeout after a series of empty poll responses. * * @author Jordi A. Albornoz Mulligan <a href="mailto:jordi@cambridgesemantics.com">jordi@cambridgesemantics.com</a> */ class EncryptedTokenAuthenticationJSONTransport extends JSONTransport { //private static final Logger log = LoggerFactory.getLogger(EncryptedTokenAuthenticationJSONTransport.class); private final HttpRequestBayeux bayeux; /** * Denotes if the auth cookie was already refreshed for this request. Used to avoid adding the cookie multiple times. If set, the value will be * {@link Boolean#TRUE}. */ private static final String AUTH_COOKIE_REFRESHED_ATTRIBUTE = "org.openanzo.server.combus.bayeux.EncryptedTokenAuthenticationJSONTransport.authCookieRefresh"; protected EncryptedTokenAuthenticationJSONTransport(HttpRequestBayeux bayeux) { super(); if (bayeux == null) { throw new AnzoRuntimeException(ExceptionConstants.COMBUS.BAYEUX_NULL); } this.bayeux = bayeux; } /* (non-Javadoc) * @see org.eclipse.cometd.JSONTransport#send(dojox.cometd.Message) */ @Override public synchronized void send(org.cometd.Message message) throws IOException { if (!bayeux.isRequestAvailable() || bayeux.getCurrentRequest() == null) { throw new IllegalStateException("EncryptedTokenAuthenticationJSONTransport requires that the current HTTP request be available. Make sure the Bayeux 'requestAvailable' init parameter for the cometd servlet is true."); } HttpServletRequest currentRequest = bayeux.getCurrentRequest(); Object attr = currentRequest.getAttribute(EncryptedTokenAuthenticator.ANZO_REFRESH_COOKIE_ATTRIBUTE); if (attr instanceof Cookie) { Cookie tokenCookie = (Cookie) attr; if (currentRequest.getAttribute(AUTH_COOKIE_REFRESHED_ATTRIBUTE) == null) { // If the cookie hasn't already been refreshed // The authenticator left us a cookie to use for refreshing the timeout. But we won't refresh // the timeout if this is a message sent to the "/meta/connect" channel since such messages // are simply poll request acknowledgments. String messageChannel = message.getChannel(); if (!AbstractBayeux.META_CONNECT.equals(messageChannel)) { HttpServletResponse response = getResponse(); response.addCookie(tokenCookie); currentRequest.setAttribute(AUTH_COOKIE_REFRESHED_ATTRIBUTE, Boolean.TRUE); } } } super.send(message); } }