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

Reply via email to