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: [email protected]
For additional commands, e-mail: [email protected]