Author: markt Date: Tue Dec 16 21:53:58 2014 New Revision: 1646104 URL: http://svn.apache.org/r1646104 Log: Remove session object from SingleSignOnMaps
Added: tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOnSessionKey.java Modified: tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOn.java tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOnEntry.java Modified: tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOn.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOn.java?rev=1646104&r1=1646103&r2=1646104&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOn.java (original) +++ tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOn.java Tue Dec 16 21:53:58 2014 @@ -19,11 +19,17 @@ package org.apache.catalina.authenticato import java.io.IOException; import java.security.Principal; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import javax.servlet.ServletException; import javax.servlet.http.Cookie; +import org.apache.catalina.Container; +import org.apache.catalina.Context; +import org.apache.catalina.Engine; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.Manager; import org.apache.catalina.Realm; import org.apache.catalina.Session; import org.apache.catalina.SessionEvent; @@ -53,6 +59,12 @@ import org.apache.catalina.valves.ValveB */ public class SingleSignOn extends ValveBase implements SessionListener { + /* The engine at the top of the container hierarchy in which this SSO Valve + * has been placed. It is used to get back to a session object from a + * SingleSignOnSessionKey and is updated when the Valve starts and stops. + */ + private Engine engine; + //------------------------------------------------------ Constructor public SingleSignOn() { @@ -79,7 +91,7 @@ public class SingleSignOn extends ValveB * The cache of single sign on identifiers, keyed by the Session that is * associated with them. */ - protected Map<Session,String> reverse = new ConcurrentHashMap<>(); + protected Map<SingleSignOnSessionKey,String> reverse = new ConcurrentHashMap<>(); /** @@ -209,7 +221,7 @@ public class SingleSignOn extends ValveB } String ssoId = null; - ssoId = reverse.get(session); + ssoId = reverse.get(new SingleSignOnSessionKey(session)); if (ssoId == null) { return; } @@ -354,7 +366,7 @@ public class SingleSignOn extends ValveB if (sso != null) { sso.addSession(this, session); } - reverse.put(session, ssoId); + reverse.put(new SingleSignOnSessionKey(session), ssoId); } @@ -367,7 +379,7 @@ public class SingleSignOn extends ValveB */ protected void deregister(String ssoId, Session session) { - reverse.remove(session); + reverse.remove(new SingleSignOnSessionKey(session)); SingleSignOnEntry sso = cache.get(ssoId); if (sso == null) { @@ -377,8 +389,8 @@ public class SingleSignOn extends ValveB sso.removeSession(session); // see if we are the last session, if so blow away ssoId - Session sessions[] = sso.findSessions(); - if (sessions == null || sessions.length == 0) { + Set<SingleSignOnSessionKey> sessions = sso.findSessions(); + if (sessions == null || sessions.size() == 0) { cache.remove(ssoId); } } @@ -404,21 +416,54 @@ public class SingleSignOn extends ValveB } // Expire any associated sessions - Session sessions[] = sso.findSessions(); - for (int i = 0; i < sessions.length; i++) { + for (SingleSignOnSessionKey ssoKey : sso.findSessions()) { if (containerLog.isTraceEnabled()) { - containerLog.trace(" Invalidating session " + sessions[i]); + containerLog.trace(" Invalidating session " + ssoKey); } // Remove from reverse cache first to avoid recursion - reverse.remove(sessions[i]); + reverse.remove(ssoKey); // Invalidate this session - sessions[i].expire(); + expire(ssoKey); } // NOTE: Clients may still possess the old single sign on cookie, // but it will be removed on the next request since it is no longer // in the cache + } + + private void expire(SingleSignOnSessionKey key) { + if (engine == null) { + // TODO Log error + return; + } + Container host = engine.findChild(key.getHostName()); + if (host == null) { + // TODO Log error + return; + } + Context context = (Context) host.findChild(key.getContextName()); + if (context == null) { + // TODO Log error + return; + } + Manager manager = context.getManager(); + if (manager == null) { + // TODO Log error + return; + } + Session session = null; + try { + session = manager.findSession(key.getSessionId()); + } catch (IOException e) { + // TODO Log error + return; + } + if (session == null) { + // TODO Log error + return; + } + session.expire(); } @@ -558,12 +603,32 @@ public class SingleSignOn extends ValveB entry.removeSession(session); // Remove the inactive session from the 'reverse' Map. - reverse.remove(session); + reverse.remove(new SingleSignOnSessionKey(session)); // If there are not sessions left in the SingleSignOnEntry, // deregister the entry. - if (entry.findSessions().length == 0) { + if (entry.findSessions().size() == 0) { deregister(ssoId); } } + + + @Override + protected synchronized void startInternal() throws LifecycleException { + Container c = getContainer(); + while (c != null && !(c instanceof Engine)) { + c = c.getParent(); + } + if (c instanceof Engine) { + engine = (Engine) c; + } + super.startInternal(); + } + + + @Override + protected synchronized void stopInternal() throws LifecycleException { + super.stopInternal(); + engine = null; + } } Modified: tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOnEntry.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOnEntry.java?rev=1646104&r1=1646103&r2=1646104&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOnEntry.java (original) +++ tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOnEntry.java Tue Dec 16 21:53:58 2014 @@ -17,6 +17,8 @@ package org.apache.catalina.authenticator; import java.security.Principal; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import javax.servlet.http.HttpServletRequest; @@ -42,7 +44,8 @@ public class SingleSignOnEntry { protected Principal principal = null; - protected Session sessions[] = new Session[0]; + protected ConcurrentHashMap<SingleSignOnSessionKey,SingleSignOnSessionKey> sessionKeys = + new ConcurrentHashMap<>(); protected String username = null; @@ -76,16 +79,13 @@ public class SingleSignOnEntry { * the SSO session. * @param session The <code>Session</code> being associated with the SSO. */ - public synchronized void addSession(SingleSignOn sso, Session session) { - for (int i = 0; i < sessions.length; i++) { - if (session == sessions[i]) - return; + public void addSession(SingleSignOn sso, Session session) { + SingleSignOnSessionKey key = new SingleSignOnSessionKey(session); + SingleSignOnSessionKey currentKey = sessionKeys.putIfAbsent(key, key); + if (currentKey == null) { + // Session not previously added + session.addSessionListener(sso); } - Session results[] = new Session[sessions.length + 1]; - System.arraycopy(sessions, 0, results, 0, sessions.length); - results[sessions.length] = session; - sessions = results; - session.addSessionListener(sso); } /** @@ -94,21 +94,16 @@ public class SingleSignOnEntry { * * @param session the <code>Session</code> to remove. */ - public synchronized void removeSession(Session session) { - Session[] nsessions = new Session[sessions.length - 1]; - for (int i = 0, j = 0; i < sessions.length; i++) { - if (session == sessions[i]) - continue; - nsessions[j++] = sessions[i]; - } - sessions = nsessions; + public void removeSession(Session session) { + SingleSignOnSessionKey key = new SingleSignOnSessionKey(session); + sessionKeys.remove(key); } /** * Returns the <code>Session</code>s associated with this SSO. */ - public synchronized Session[] findSessions() { - return (this.sessions); + public Set<SingleSignOnSessionKey> findSessions() { + return sessionKeys.keySet(); } /** Added: tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOnSessionKey.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOnSessionKey.java?rev=1646104&view=auto ============================================================================== --- tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOnSessionKey.java (added) +++ tomcat/trunk/java/org/apache/catalina/authenticator/SingleSignOnSessionKey.java Tue Dec 16 21:53:58 2014 @@ -0,0 +1,122 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.authenticator; + +import java.io.Serializable; + +import org.apache.catalina.Context; +import org.apache.catalina.Session; + +/** + * Key used by SSO to identify a session. This key is used rather than the + * actual session to facilitate the replication of the SSO information + * across a cluster where replicating the entire session would generate + * significant, unnecessary overhead. + * + */ +public class SingleSignOnSessionKey implements Serializable { + + private static final long serialVersionUID = 1L; + + private final String sessionId; + private final String contextName; + private final String hostName; + + public SingleSignOnSessionKey(Session session) { + this.sessionId = session.getId(); + Context context = session.getManager().getContext(); + this.contextName = context.getName(); + this.hostName = context.getParent().getName(); + } + + public String getSessionId() { + return sessionId; + } + + public String getContextName() { + return contextName; + } + + public String getHostName() { + return hostName; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((sessionId == null) ? 0 : sessionId.hashCode()); + result = prime * result + + ((contextName == null) ? 0 : contextName.hashCode()); + result = prime * result + + ((hostName == null) ? 0 : hostName.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + SingleSignOnSessionKey other = (SingleSignOnSessionKey) obj; + if (sessionId == null) { + if (other.sessionId != null) { + return false; + } + } else if (!sessionId.equals(other.sessionId)) { + return false; + } + if (contextName == null) { + if (other.contextName != null) { + return false; + } + } else if (!contextName.equals(other.contextName)) { + return false; + } + if (hostName == null) { + if (other.hostName != null) { + return false; + } + } else if (!hostName.equals(other.hostName)) { + return false; + } + return true; + } + + @Override + public String toString() { + // Session ID is 32. Standard text is 36. Host could easily be 20+. + // Context could be anything from 0 upwards. 128 seems like a reasonable + // size to accommodate most cases without being too big. + StringBuilder sb = new StringBuilder(128); + sb.append("Host: ["); + sb.append(hostName); + sb.append("], Context: ["); + sb.append(contextName); + sb.append("], SessionID: ["); + sb.append(sessionId); + sb.append("]"); + return sb.toString(); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org