From 909f7262b9e6870bdfcb14c6dc992e4299b3c085 Mon Sep 17 00:00:00 2001 From: David Matejcek Date: Thu, 30 Oct 2014 08:18:38 +0100 Subject: [PATCH 1/4] GLASSFISH-21148 Fixed parsing principal from metadata - prinicpal was parsed, but metadata were not updated --- .../ha/authenticator/HASingleSignOnEntry.java | 111 +++++++++--------- 1 file changed, 54 insertions(+), 57 deletions(-) diff --git a/appserver/web/web-ha/src/main/java/org/glassfish/web/ha/authenticator/HASingleSignOnEntry.java b/appserver/web/web-ha/src/main/java/org/glassfish/web/ha/authenticator/HASingleSignOnEntry.java index b9909b1f2c2..56e6f5839f1 100644 --- a/appserver/web/web-ha/src/main/java/org/glassfish/web/ha/authenticator/HASingleSignOnEntry.java +++ b/appserver/web/web-ha/src/main/java/org/glassfish/web/ha/authenticator/HASingleSignOnEntry.java @@ -41,20 +41,25 @@ package org.glassfish.web.ha.authenticator; import com.sun.enterprise.container.common.spi.util.JavaEEIOUtils; + import org.apache.catalina.Container; import org.apache.catalina.core.StandardContext; - import org.apache.catalina.Session; import org.apache.catalina.authenticator.SingleSignOn; import org.apache.catalina.authenticator.SingleSignOnEntry; +import org.glassfish.web.ha.session.management.HAStoreBase; import java.io.*; import java.security.Principal; +import java.util.logging.Level; +import java.util.logging.Logger; /** * @author Shing Wai Chan */ public class HASingleSignOnEntry extends SingleSignOnEntry { + private static final Logger logger = HAStoreBase._logger; + protected long maxIdleTime; protected JavaEEIOUtils ioUtils; @@ -73,36 +78,9 @@ public HASingleSignOnEntry(Container container, HASingleSignOnEntryMetadata m, m.getLastAccessTime(), m.getMaxIdleTime(), m.getVersion(), ioUtils); - ByteArrayInputStream bais = null; - BufferedInputStream bis = null; - ObjectInputStream ois = null; - try { - bais = new ByteArrayInputStream(m.getPrincipalBytes()); - bis = new BufferedInputStream(bais); - ois = ioUtils.createObjectInputStream(bis, true, this.getClass().getClassLoader()); - this.principal = (Principal)ois.readObject(); - } catch(Exception ex) { - throw new IllegalStateException(ex); - } finally { - if (bais != null) { - try { - bais.close(); - } catch(IOException ex) { - } - } - if (bis != null) { - try { - bis.close(); - } catch(IOException ex) { - } - } - if (ois != null) { - try { - ois.close(); - } catch(IOException ex) { - } - } - } + // GLASSFISH-21148: constructor called with null - don't forget to update metadata! + this.principal = parsePrincipal(m); + this.metadata.principalBytes = m.getPrincipalBytes() == null ? null : m.getPrincipalBytes().clone(); for (HASessionData data: m.getHASessionDataSet()) { StandardContext context = (StandardContext)container.findChild(data.getContextPath()); @@ -112,24 +90,29 @@ public HASingleSignOnEntry(Container container, HASingleSignOnEntryMetadata m, } catch(IOException ex) { throw new IllegalStateException(ex); } - sessions.add(session); + if (session != null) { + sessions.add(session); + } } + logger.log(Level.FINER, "Loaded HA SSO entry from metadata. Principal: {}", this.principal); } + // TODO: javadoc: difference between principal.getName and userName? public HASingleSignOnEntry(String id, Principal principal, String authType, String username, String realmName, long lastAccessTime, long maxIdleTime, long version, JavaEEIOUtils ioUtils) { - + super(id, version, principal, authType, username, realmName); this.lastAccessTime = lastAccessTime; this.maxIdleTime = maxIdleTime; this.ioUtils = ioUtils; - metadata = new HASingleSignOnEntryMetadata( + this.metadata = new HASingleSignOnEntryMetadata( id, version, convertToByteArray(principal), authType, username, realmName, lastAccessTime, maxIdleTime); + logger.log(Level.FINER, "Created HA SSO entry. Principal: {}", this.principal); } public HASingleSignOnEntryMetadata getMetadata() { @@ -171,39 +154,53 @@ public long incrementAndGetVersion() { return ver; } - // convert a Serializable object into byte array - private byte[] convertToByteArray(Object obj) { - ByteArrayOutputStream baos = null; + /** convert a principal into byte array */ + private byte[] convertToByteArray(Principal obj) { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); BufferedOutputStream bos = null; ObjectOutputStream oos = null; try { - baos = new ByteArrayOutputStream(); bos = new BufferedOutputStream(baos); oos = ioUtils.createObjectOutputStream(bos, true); oos.writeObject(obj); + oos.flush(); + return baos.toByteArray(); } catch(Exception ex) { throw new IllegalStateException(ex); } finally { - if (baos != null) { - try { - baos.close(); - } catch(Exception ex) { - } - } - if (bos != null) { - try { - bos.close(); - } catch(Exception ex) { - } - } - if (oos != null) { - try { - oos.close(); - } catch(Exception ex) { - } - } + closeSilently(baos); + closeSilently(bos); + closeSilently(oos); } + } + + /** Parse a principal from metadata */ + private Principal parsePrincipal(HASingleSignOnEntryMetadata m) { + ByteArrayInputStream bais = null; + BufferedInputStream bis = null; + ObjectInputStream ois = null; + try { + bais = new ByteArrayInputStream(m.getPrincipalBytes()); + bis = new BufferedInputStream(bais); + ois = ioUtils.createObjectInputStream(bis, true, this.getClass().getClassLoader()); + return (Principal) ois.readObject(); + } catch (Exception ex) { + throw new IllegalStateException(ex); + } finally { + closeSilently(bais); + closeSilently(bis); + closeSilently(ois); + } + } - return baos.toByteArray(); + private void closeSilently(Closeable closeable) { + if (closeable == null) { + return; + } + try { + closeable.close(); + } catch(Exception ex) { + // nothing + } } } From 4258a2da830b5cd28aa50fdb39704bde9ed6e8f1 Mon Sep 17 00:00:00 2001 From: David Matejcek Date: Thu, 30 Oct 2014 08:19:49 +0100 Subject: [PATCH 2/4] GLASSFISH-21148 More descriptive exception messages --- .../glassfish/web/ha/authenticator/HASingleSignOnEntry.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/appserver/web/web-ha/src/main/java/org/glassfish/web/ha/authenticator/HASingleSignOnEntry.java b/appserver/web/web-ha/src/main/java/org/glassfish/web/ha/authenticator/HASingleSignOnEntry.java index 56e6f5839f1..c9a70259e00 100644 --- a/appserver/web/web-ha/src/main/java/org/glassfish/web/ha/authenticator/HASingleSignOnEntry.java +++ b/appserver/web/web-ha/src/main/java/org/glassfish/web/ha/authenticator/HASingleSignOnEntry.java @@ -88,7 +88,7 @@ public HASingleSignOnEntry(Container container, HASingleSignOnEntryMetadata m, try { session = context.getManager().findSession(data.getSessionId()); } catch(IOException ex) { - throw new IllegalStateException(ex); + throw new IllegalStateException("Cannot find the session: " + data.getSessionId(), ex); } if (session != null) { sessions.add(session); @@ -166,7 +166,7 @@ private byte[] convertToByteArray(Principal obj) { oos.flush(); return baos.toByteArray(); } catch(Exception ex) { - throw new IllegalStateException(ex); + throw new IllegalStateException("Could not convert principal to byte array", ex); } finally { closeSilently(baos); closeSilently(bos); @@ -185,7 +185,7 @@ private Principal parsePrincipal(HASingleSignOnEntryMetadata m) { ois = ioUtils.createObjectInputStream(bis, true, this.getClass().getClassLoader()); return (Principal) ois.readObject(); } catch (Exception ex) { - throw new IllegalStateException(ex); + throw new IllegalStateException("Could not parse principal from HA-SSO Metadata", ex); } finally { closeSilently(bais); closeSilently(bis); From eedadf5d8dae2323aaf05bfcf0fee121b960e2a8 Mon Sep 17 00:00:00 2001 From: David Matejcek Date: Thu, 30 Oct 2014 08:36:39 +0100 Subject: [PATCH 3/4] GLASSFISH-21219 Using HashMap instead of HashSet - Session.hashCode may change (serializable) --- .../authenticator/SingleSignOnEntry.java | 54 +++++++++---------- 1 file changed, 24 insertions(+), 30 deletions(-) diff --git a/appserver/web/web-core/src/main/java/org/apache/catalina/authenticator/SingleSignOnEntry.java b/appserver/web/web-core/src/main/java/org/apache/catalina/authenticator/SingleSignOnEntry.java index 12c9751e009..006b685c48a 100644 --- a/appserver/web/web-core/src/main/java/org/apache/catalina/authenticator/SingleSignOnEntry.java +++ b/appserver/web/web-core/src/main/java/org/apache/catalina/authenticator/SingleSignOnEntry.java @@ -58,38 +58,39 @@ package org.apache.catalina.authenticator; -import org.apache.catalina.Session; -import org.apache.catalina.core.StandardServer; - import java.security.Principal; -import java.util.HashSet; -import java.util.Set; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.atomic.AtomicLong; import java.util.logging.Level; import java.util.logging.Logger; +import org.apache.catalina.Session; +import org.apache.catalina.core.StandardServer; + /** - * A private class representing entries in the cache of authenticated users. + * A class representing entries in the cache of authenticated users. */ public class SingleSignOnEntry { private static final Logger log = StandardServer.log; - protected String id = null; + protected final String id; - protected String authType = null; + protected final String authType; - protected Principal principal = null; + /** Reset by HASingleSignOnEntry */ + protected Principal principal; - protected Set sessions = new HashSet(); + protected final Map sessions = new HashMap(); - protected String username = null; + protected final String username; - protected String realmName = null; + protected final String realmName; protected long lastAccessTime; - protected AtomicLong version = null; + protected final AtomicLong version; public SingleSignOnEntry(String id, long ver, Principal principal, String authType, @@ -107,20 +108,20 @@ public SingleSignOnEntry(String id, long ver, /** * Adds the given session to this SingleSignOnEntry if it does not * already exist. - * + * * @return true if the session was added, false otherwise */ public synchronized boolean addSession(SingleSignOn sso, Session session) { - boolean result = sessions.add(session); - if (result) { + final Session oldEntry = sessions.put(session.getId(), session); + if (oldEntry == null) { session.addSessionListener(sso); } - - return true; + return oldEntry == null; } public synchronized void removeSession(Session session) { - sessions.remove(session); + final Session removed = sessions.remove(session.getId()); + log.warning("session " + session.getId() + "found (and removed): " + removed); } @@ -132,7 +133,7 @@ public synchronized void removeSession(Session session) { * associated with it, and false otherwise */ public synchronized boolean isEmpty() { - return (sessions.size() == 0); + return sessions.isEmpty(); } @@ -141,23 +142,16 @@ public synchronized boolean isEmpty() { * */ public synchronized void expireSessions() { - for (Session session: sessions) { + for (Session session: sessions.values()) { if (log.isLoggable(Level.FINE)) { - log.log(Level.FINE, " Invalidating session " + session); } - - //6406580 START - /* - // Invalidate this session - session.expire(); - */ + // Invalidate this session // if it is not already invalid(ated) - if( (session).getIsValid() ) { + if(session.getIsValid() ) { session.expire(); } - //6406580 END } } From 019a52ef8a542b77432548a7b6fbbb585c323a93 Mon Sep 17 00:00:00 2001 From: David Matejcek Date: Thu, 30 Oct 2014 08:37:25 +0100 Subject: [PATCH 4/4] GLASSFISH-21219 Using HashMap instead of HashSet (HA/SSO) --- .../org/glassfish/web/ha/authenticator/HASingleSignOnEntry.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appserver/web/web-ha/src/main/java/org/glassfish/web/ha/authenticator/HASingleSignOnEntry.java b/appserver/web/web-ha/src/main/java/org/glassfish/web/ha/authenticator/HASingleSignOnEntry.java index c9a70259e00..7d0cedce1e6 100644 --- a/appserver/web/web-ha/src/main/java/org/glassfish/web/ha/authenticator/HASingleSignOnEntry.java +++ b/appserver/web/web-ha/src/main/java/org/glassfish/web/ha/authenticator/HASingleSignOnEntry.java @@ -91,7 +91,7 @@ public HASingleSignOnEntry(Container container, HASingleSignOnEntryMetadata m, throw new IllegalStateException("Cannot find the session: " + data.getSessionId(), ex); } if (session != null) { - sessions.add(session); + sessions.put(data.getSessionId(), session); } } logger.log(Level.FINER, "Loaded HA SSO entry from metadata. Principal: {}", this.principal);