package com.norteksoft.acs.web.filter; import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.Map; 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.HttpSession; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jasig.cas.client.session.SessionMappingStorage; import org.jasig.cas.client.util.AbstractConfigurationFilter; import org.jasig.cas.client.util.CommonUtils; import org.jasig.cas.client.util.XmlUtils; /** * Implements the Single Sign Out protocol. It handles registering the session * and destroying the session. * * @author Scott Battaglia * @version $Revision$ $Date$ * @since 3.1 */ public final class SingleSignOutFilter extends AbstractConfigurationFilter { /** * The name of the artifact parameter. This is used to capture the session * identifier. */ private String artifactParameterName = "ticket"; // private static SessionMappingStorage SESSION_MAPPING_STORAGE = new HashMapBackedSessionMappingStorage(); private static SessionMappingStorage SESSION_MAPPING_STORAGE = new SessionStorage(); private static Log log = LogFactory.getLog(SingleSignOutFilter.class); public void init(final FilterConfig filterConfig) throws ServletException { if (!isIgnoreInitConfiguration()) { setArtifactParameterName(getPropertyFromInitParams(filterConfig, "artifactParameterName", "ticket")); } init(); } public void init() { CommonUtils.assertNotNull(this.artifactParameterName, "artifactParameterName cannot be null."); CommonUtils.assertNotNull(SESSION_MAPPING_STORAGE, "sessionMappingStorage cannote be null."); } public void setArtifactParameterName(final String artifactParameterName) { this.artifactParameterName = artifactParameterName; } public void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException { final HttpServletRequest request = (HttpServletRequest) servletRequest; final String logoutRequest = request.getParameter("logoutRequest"); if (CommonUtils.isNotBlank(logoutRequest)) { if (log.isTraceEnabled()) { log.trace("Logout request=[" + logoutRequest + "]"); } final String sessionIdentifier = XmlUtils.getTextForElement(logoutRequest, "SessionIndex"); if (CommonUtils.isNotBlank(sessionIdentifier)) { final HttpSession session = SESSION_MAPPING_STORAGE.removeSessionByMappingId(sessionIdentifier); if (session != null) { String sessionID = session.getId(); if (log.isDebugEnabled()) { log.debug("Invalidating session [" + sessionID + "] for ST [" + sessionIdentifier + "]"); } try { session.invalidate(); } catch (final IllegalStateException e) { log.debug(e, e); } } return; } } else { final String artifact = request.getParameter(this.artifactParameterName); final HttpSession session = request.getSession(); if (log.isDebugEnabled() && session != null) { log.debug("Storing session identifier for " + session.getId()); } if (CommonUtils.isNotBlank(artifact)) { try { SESSION_MAPPING_STORAGE.removeBySessionById(session.getId()); } catch (final Exception e) { // ignore if the session is already marked as invalid. // Nothing we can do! } SESSION_MAPPING_STORAGE.addSessionById(artifact, session); } } filterChain.doFilter(servletRequest, servletResponse); } public void setSessionMappingStorage(final SessionMappingStorage storage) { SESSION_MAPPING_STORAGE = storage; } public static SessionMappingStorage getSessionMappingStorage() { return SESSION_MAPPING_STORAGE; } public void destroy() { } final static class SessionStorage implements SessionMappingStorage { private final Map<String, HttpSession> MANAGED_SESSIONS = new HashMap<String, HttpSession>(); private final Map<String, String> ID_TO_SESSION_KEY_MAPPING = new HashMap<String, String>(); private final Log log = LogFactory.getLog(getClass()); public synchronized void addSessionById(String mappingId, HttpSession session) { ID_TO_SESSION_KEY_MAPPING.put(session.getId(), mappingId); MANAGED_SESSIONS.put(mappingId, session); } protected synchronized String getSTBySessionId(String sessionId){ return ID_TO_SESSION_KEY_MAPPING.get(sessionId); } public synchronized void removeBySessionById(String sessionId) { if (log.isDebugEnabled()) { log.debug("Attempting to remove Session=[" + sessionId + "]"); } final String key = ID_TO_SESSION_KEY_MAPPING.get(sessionId); if (log.isDebugEnabled()) { if (key != null) { log.debug("Found mapping for session. Session Removed."); } else { log.debug("No mapping for session found. Ignoring."); } } MANAGED_SESSIONS.remove(key); ID_TO_SESSION_KEY_MAPPING.remove(sessionId); } public synchronized HttpSession removeSessionByMappingId(String mappingId) { final HttpSession session = MANAGED_SESSIONS.get(mappingId); if (session != null) { removeBySessionById(session.getId()); } return session; } Collection<HttpSession> values(){ return MANAGED_SESSIONS.values(); } } }