[jboss-cvs] JBossAS SVN: r96668 - in trunk/tomcat/src/main/java/org/jboss/web/tomcat/service: session and 1 other directory.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Fri Nov 20 18:38:30 EST 2009


Author: bstansberry at jboss.com
Date: 2009-11-20 18:38:29 -0500 (Fri, 20 Nov 2009)
New Revision: 96668

Modified:
   trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/deployers/TomcatDeployer.java
   trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/deployers/TomcatDeployerMBean.java
   trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/deployers/TomcatService.java
   trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/deployers/TomcatServiceMBean.java
   trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/session/JBossManager.java
   trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/session/SessionIDGenerator.java
Log:
[JBAS-7475] Sync sessiond id generation with StandardManager

Modified: trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/deployers/TomcatDeployer.java
===================================================================
--- trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/deployers/TomcatDeployer.java	2009-11-20 22:47:23 UTC (rev 96667)
+++ trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/deployers/TomcatDeployer.java	2009-11-20 23:38:29 UTC (rev 96668)
@@ -281,22 +281,6 @@
       this.sessionCookieForSSOAuth = sessionC;
    }
 
-   /**
-    * The SessionIdAlphabet is the set of characters used to create a session Id
-    */
-   public void setSessionIdAlphabet(String sessionIdAlphabet)
-   {
-      SessionIDGenerator.getInstance().setSessionIdAlphabet(sessionIdAlphabet);
-   }
-
-   /**
-    * The SessionIdAlphabet is the set of characters used to create a session Id
-    */
-   public String getSessionIdAlphabet()
-   {
-      return SessionIDGenerator.getInstance().getSessionIdAlphabet();
-   }
-
    public String getConfigFile()
    {
       return serverConfigFile;

Modified: trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/deployers/TomcatDeployerMBean.java
===================================================================
--- trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/deployers/TomcatDeployerMBean.java	2009-11-20 22:47:23 UTC (rev 96667)
+++ trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/deployers/TomcatDeployerMBean.java	2009-11-20 23:38:29 UTC (rev 96668)
@@ -54,16 +54,6 @@
     */
    public void setDomain(String domainName);
 
-   /**
-    * The SessionIdAlphabet is the set of characters used to create a session Id
-    */
-   public void setSessionIdAlphabet(String sessionIdAlphabet);
-
-   /**
-    * The SessionIdAlphabet is the set of characters used to create a session Id
-    */
-   public String getSessionIdAlphabet();
-
    /** */
    public String getContextMBeanCode();
 

Modified: trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/deployers/TomcatService.java
===================================================================
--- trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/deployers/TomcatService.java	2009-11-20 22:47:23 UTC (rev 96667)
+++ trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/deployers/TomcatService.java	2009-11-20 23:38:29 UTC (rev 96668)
@@ -64,6 +64,7 @@
 import org.jboss.web.tomcat.metadata.ServiceMetaData;
 import org.jboss.web.tomcat.metadata.ValveMetaData;
 import org.jboss.web.tomcat.security.HttpServletRequestPolicyContextHandler;
+import org.jboss.web.tomcat.service.session.SessionIDGenerator;
 import org.jboss.xb.binding.Unmarshaller;
 import org.jboss.xb.binding.UnmarshallerFactory;
 import org.jboss.xb.binding.sunday.unmarshalling.SchemaBinding;
@@ -508,7 +509,7 @@
 
    public String getSessionIdAlphabet()
    {
-      return tomcatDeployer == null ? null : tomcatDeployer.getSessionIdAlphabet();
+      return SessionIDGenerator.getSessionIdAlphabet();
    }
 
    public String getSubjectAttributeName()
@@ -564,8 +565,7 @@
 
    public void setSessionIdAlphabet(String sessionIdAlphabet)
    {
-      if (tomcatDeployer != null)
-         tomcatDeployer.setSessionIdAlphabet(sessionIdAlphabet);
+      SessionIDGenerator.setSessionIdAlphabet(sessionIdAlphabet);
    }
 
    public void setSubjectAttributeName(String name)

Modified: trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/deployers/TomcatServiceMBean.java
===================================================================
--- trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/deployers/TomcatServiceMBean.java	2009-11-20 22:47:23 UTC (rev 96667)
+++ trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/deployers/TomcatServiceMBean.java	2009-11-20 23:38:29 UTC (rev 96668)
@@ -33,4 +33,14 @@
 public interface TomcatServiceMBean extends TomcatDeployerMBean, ServiceMBean
 {
    public void setTomcatDeployer(TomcatDeployer tomcatDeployer);
+
+   /**
+    * The SessionIdAlphabet is the set of characters used to create a session Id
+    */
+   public void setSessionIdAlphabet(String sessionIdAlphabet);
+
+   /**
+    * The SessionIdAlphabet is the set of characters used to create a session Id
+    */
+   public String getSessionIdAlphabet();
 }

Modified: trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/session/JBossManager.java
===================================================================
--- trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/session/JBossManager.java	2009-11-20 22:47:23 UTC (rev 96667)
+++ trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/session/JBossManager.java	2009-11-20 23:38:29 UTC (rev 96668)
@@ -185,7 +185,7 @@
    protected PropertyChangeSupport support_ = new PropertyChangeSupport(this);
 
    /** Generates ids for new sessions */
-   protected SessionIDGenerator sessionIDGenerator_= SessionIDGenerator.getInstance();;
+   protected SessionIDGenerator sessionIDGenerator_= new SessionIDGenerator();;
 
    /** Our containing engine's jvmRoute (if it has one) */
    protected String jvmRoute_;
@@ -979,27 +979,23 @@
    
    public void setAlgorithm(String algorithm)
    {
-      if (algorithm != null && algorithm.length() > 0)
-      {
-         log_.debug(getClass().getSimpleName() + " is ignoring the algorithm algorithm");
-      }
+      sessionIDGenerator_.setAlgorithm(algorithm);
    }
    
    public void setEntropy(String entropy)
    {
-      if (entropy != null && entropy.length() > 0)
-      {
-         log_.debug(getClass().getSimpleName() + " is ignoring the entropy algorithm");
-      }
+      sessionIDGenerator_.setEntropy(entropy);
    }
    
    public void setRandomClass(String randomClass)
    {
-      if (randomClass != null && randomClass.length() > 0)
-      {
-         log_.debug(getClass().getSimpleName() + " is ignoring the randomClass algorithm");
-      }
+      sessionIDGenerator_.setRandomClass(randomClass);
    }
+   
+   public void setRandomFile(String randomFile)
+   {
+      sessionIDGenerator_.setRandomFile(randomFile);
+   }
 
    // ------------------------------------------------------------------ Protected
 

Modified: trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/session/SessionIDGenerator.java
===================================================================
--- trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/session/SessionIDGenerator.java	2009-11-20 22:47:23 UTC (rev 96667)
+++ trunk/tomcat/src/main/java/org/jboss/web/tomcat/service/session/SessionIDGenerator.java	2009-11-20 23:38:29 UTC (rev 96668)
@@ -1,6 +1,6 @@
 /*
  * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * Copyright 200*, Red Hat, Inc. and individual contributors
  * as indicated by the @author tags. See the copyright.txt file in the
  * distribution for a full listing of individual contributors.
  *
@@ -21,52 +21,64 @@
  */
 package org.jboss.web.tomcat.service.session;
 
-import java.util.Random;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.AccessController;
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
+import java.security.PrivilegedAction;
 import java.security.SecureRandom;
+import java.util.Random;
 
+import org.apache.catalina.Globals;
 import org.jboss.logging.Logger;
 
 /**
- * Unique session id generator
+ * Unique session id generator.
  *
  * @author Ben Wang
+ * @author Brian Stansberry
  */
 public class SessionIDGenerator
 {
-   protected final static int SESSION_ID_BYTES = 16; // We want 16 Bytes for the session-id
-   protected final static String SESSION_ID_HASH_ALGORITHM = "MD5";
-   protected final static String SESSION_ID_RANDOM_ALGORITHM = "SHA1PRNG";
-   protected final static String SESSION_ID_RANDOM_ALGORITHM_ALT = "IBMSecureRandom";
+   public static final String DEFAULT_SESSION_ID_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-_";
+   public static final String DEFAULT_RANDOM_FILE = "/dev/urandom";
+   public static final String DEFAULT_RANDOM_CLASS = SecureRandom.class.getName();
+   public static final int    SESSION_ID_BYTES = 16; // We want 16 Bytes for the session-id
+   public static final String SESSION_ID_HASH_ALGORITHM = "MD5";
+   
+   private static char[] sessionIdAlphabet = DEFAULT_SESSION_ID_ALPHABET.toCharArray();
+   
    protected Logger log = Logger.getLogger(SessionIDGenerator.class);
 
-   protected MessageDigest digest = null;
-   protected Random random = null;
-   protected static final SessionIDGenerator s_ = new SessionIDGenerator();
+   private String randomFile = DEFAULT_RANDOM_FILE;
+   private String randomClass = DEFAULT_RANDOM_CLASS;
+   private String algorithm = SESSION_ID_HASH_ALGORITHM;
+   private String entropy;   
+   private DataInputStream randomIS;  
+   private MessageDigest digest;
+   private Random random; 
    
-   protected String sessionIdAlphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-_";
+   // ------------------------------------------------------------  Static
 
-   public static SessionIDGenerator getInstance()
-   {
-      return s_;
-   }
-
    /**
     * The SessionIdAlphabet is the set of characters used to create a session Id
     */
-   public void setSessionIdAlphabet(String sessionIdAlphabet) 
+   public static void setSessionIdAlphabet(String alphabet) 
    {
-      if (sessionIdAlphabet.length() != 65) {
+      if (alphabet.length() != 65) {
          throw new IllegalArgumentException("SessionIdAlphabet must be exactly 65 characters long");
       }
 
-      checkDuplicateChars(sessionIdAlphabet);
+      checkDuplicateChars(alphabet);
 
-      this.sessionIdAlphabet = sessionIdAlphabet;
+      SessionIDGenerator.sessionIdAlphabet = alphabet.toCharArray();
    }
 
-   protected void checkDuplicateChars(String sessionIdAlphabet) {
+   protected static void checkDuplicateChars(String sessionIdAlphabet) {
       char[] alphabet = sessionIdAlphabet.toCharArray();
       for (int i=0; i < alphabet.length; i++) {
           if (!uniqueChar(alphabet[i], sessionIdAlphabet)) {
@@ -76,7 +88,7 @@
    }
       
    // does a character appear in the String once and only once?
-   protected boolean uniqueChar(char c, String s) {
+   protected static boolean uniqueChar(char c, String s) {
        int firstIndex = s.indexOf(c);
        if (firstIndex == -1) return false;
        return s.indexOf(c, firstIndex + 1) == -1;
@@ -85,47 +97,138 @@
    /**
     * The SessionIdAlphabet is the set of characters used to create a session Id
     */
-   public String getSessionIdAlphabet() {
-      return this.sessionIdAlphabet;
-   }
+   public static String getSessionIdAlphabet() {
+      return new String(sessionIdAlphabet);
+   }   
    
-   public synchronized String getSessionId()
+   // ------------------------------------------------------------  Properties
+   
+   public String getAlgorithm()
    {
-      String id = generateSessionId();
-      if (log.isTraceEnabled())
-         log.trace("getSessionId() called: " + id);
-      return id;
+      return algorithm;
    }
 
+   public void setAlgorithm(String algorithm)
+   {
+      this.algorithm = algorithm;
+   }
 
    /**
-    * Generate a session-id that is not guessable
-    *
-    * @return generated session-id
+    * Return the entropy increaser value, or compute a semi-useful value
+    * if this String has not yet been set.
     */
-   protected synchronized String generateSessionId()
+   public String getEntropy()
    {
-      if (this.digest == null)
+      // Calculate a semi-useful value if this has not been set
+      if (this.entropy == null)
       {
-         this.digest = getDigest();
+         // First, try to use APR to get a crypto secure entropy value         
+         try
+         {
+            byte[] result = new byte[32];
+            Class<?> jniOSClazz = Class.forName("org.apache.tomcat.jni.OS");
+            Class<?> paramTypes[] = new Class[]{ result.getClass(), int.class };
+            Object paramValues[] = new Object[]{ result, Integer.valueOf(32) };
+            jniOSClazz.getMethod("random", paramTypes).invoke(null, paramValues);
+            this.entropy = new String(result);
+         }
+         catch (Throwable t)
+         {
+            // Fall back on our hash code
+            this.entropy = this.toString();
+         }
       }
 
-      if (this.random == null)
-      {
-         this.random = getRandom();
-      }
+      return (this.entropy);
 
-      byte[] bytes = new byte[SESSION_ID_BYTES];
+   }
 
-      // get random bytes
-      this.random.nextBytes(bytes);
+   /**
+    * Set the entropy increaser value.
+    *
+    * @param entropy The new entropy increaser value
+    */
+   public void setEntropy(String entropy)
+   {
+      this.entropy = entropy;
+   }
 
+   public String getRandomClass()
+   {
+      return randomClass;
+   }
+
+   public void setRandomClass(String randomClass)
+   {
+      this.randomClass = randomClass;
+   }
+
+   public String getRandomFile()
+   {
+      return randomFile;
+   }
+
+   public void setRandomFile(String randomFile)
+   {
+      this.randomFile = randomFile;
+   }
+   
+   // ----------------------------------------------------------------  Public
+   
+   public synchronized String getSessionId()
+   {
+      return generateSessionId();
+   } 
+
+   // -------------------------------------------------------------  Protected
+   
+   /**
+    * Generate a session-id that is not guessable
+    *
+    * @return generated session-id
+    */
+   protected synchronized String generateSessionId()
+   {
+      byte[] bytes = getRandomBytes();
+
       // Hash the random bytes
-      bytes = this.digest.digest(bytes);
+      bytes = getDigest().digest(bytes);
 
       // Render the result as a String of hexadecimal digits
       return encode(bytes);
    }
+   
+   protected byte[] getRandomBytes()
+   {
+      byte[] bytes = new byte[SESSION_ID_BYTES];
+      
+      // Try to read from OS source, e.g. /dev/urandom
+      InputStream randomIS = getRandomInputStream();
+      if (randomIS != null)
+      {
+         try 
+         {
+            if (randomIS.read(bytes) == bytes.length) 
+            {
+                return bytes;
+            }
+            log.debug("Failed to read " + bytes.length + 
+                      " bytes from random source; closing stream");
+         } 
+         catch (Exception ex) 
+         {
+            // Ignore
+         }
+        
+         closeRandomInputStream();
+         
+      }
+      
+      // Fall back on a java.util.Random
+      getRandom().nextBytes(bytes);
+      
+      return bytes;
+   }
 
    /**
     * Encode the bytes into a String with a slightly modified Base64-algorithm
@@ -138,7 +241,7 @@
    protected String encode(byte[] data)
    {
       char[] out = new char[((data.length + 2) / 3) * 4];
-      char[] alphabet = this.sessionIdAlphabet.toCharArray();
+      char[] alphabet = sessionIdAlphabet;
 
       //
       // 3 bytes encode to 4 chars.  Output is always an even
@@ -180,35 +283,35 @@
     */
    protected synchronized Random getRandom()
    {
-      long seed;
-      Random random = null;
+      if (this.random == null)
+      {
+         Random r = null;
 
-      // Mix up the seed a bit
-      seed = System.currentTimeMillis();
-      seed ^= Runtime.getRuntime().freeMemory();
+         // Mix up the seed a bit
+         long seed = System.nanoTime();
+         char entropy[] = getEntropy().toCharArray();
+         for (int i = 0; i < entropy.length; i++)
+         {
+            long update = ((byte) entropy[i]) << ((i % 8) * 8);
+            seed ^= update;
+         }
 
-      try
-      {
-         random = SecureRandom.getInstance(SESSION_ID_RANDOM_ALGORITHM);
-      }
-      catch (NoSuchAlgorithmException e)
-      {
          try
          {
-            random = SecureRandom.getInstance(SESSION_ID_RANDOM_ALGORITHM_ALT);
+            Class<?> clazz = Class.forName(randomClass);
+            r = (Random) clazz.newInstance();
          }
-         catch (NoSuchAlgorithmException e_alt)
+         catch (Exception e)
          {
-            log.error("Could not generate SecureRandom for session-id randomness", e);
-            log.error("Could not generate SecureRandom for session-id randomness", e_alt);
-            return null;
+            log.warn("Exception initializing random number generator of class " + randomClass, e);
+            r = new java.util.Random();
          }
+
+         // set the generated seed for this PRNG
+         r.setSeed(seed);
+         this.random = r;
       }
-
-      // set the generated seed for this PRNG
-      random.setSeed(seed);
-
-      return random;
+      return this.random;
    }
 
    /**
@@ -218,19 +321,100 @@
     */
    protected synchronized MessageDigest getDigest()
    {
-      MessageDigest digest = null;
+      if (this.digest == null)
+      {
+         MessageDigest d = null;
+         try
+         {
+            d = MessageDigest.getInstance(algorithm);
+         }
+         catch (NoSuchAlgorithmException e)
+         {
+            log.error("MessageDigest algorithm " + algorithm + " is unavailable", e);
+            if (SESSION_ID_HASH_ALGORITHM.equals(algorithm) == false)
+            {
+               try
+               {
+                  d = MessageDigest.getInstance(SESSION_ID_HASH_ALGORITHM);
+               }
+               catch (NoSuchAlgorithmException f)
+               {
+                  log.error("MessageDigest algorithm " + SESSION_ID_HASH_ALGORITHM + " is unavailable", e);
+               }
+            }
+         }
 
+         this.digest = d;
+      }
+
+      return this.digest;
+   }
+   
+   // ---------------------------------------------------------------  Private
+   
+   private InputStream getRandomInputStream()
+   {
+      if (this.randomIS == null && this.randomFile != null)
+      {
+         if (Globals.IS_SECURITY_ENABLED)
+         {
+            AccessController.doPrivileged(new PrivilegedAction<Object>() {
+
+               public Object run()
+               {
+                  openRandomInputStream();
+                  return null;
+               }
+               
+            });
+         }
+         else 
+         {
+            openRandomInputStream();
+         }
+      }
+      return this.randomIS;
+   }
+   
+   private void openRandomInputStream()
+   {
       try
       {
-         digest = MessageDigest.getInstance(SESSION_ID_HASH_ALGORITHM);
+         File f = new File(this.randomFile);
+         if (f.exists())
+         {
+            this.randomIS = new DataInputStream(new FileInputStream(f));
+            this.randomIS.readLong();
+            if (log.isDebugEnabled())
+            {
+               log.debug("Opened " + this.randomFile);
+            }
+         }
       }
-      catch (NoSuchAlgorithmException e)
+      catch (IOException ex)
       {
-         log.error("Could not generate MessageDigest for session-id hashing", e);
-         return null;
+         log.warn("Error reading " + this.randomFile, ex);
+         closeRandomInputStream();
       }
+   }
+   
+   private void closeRandomInputStream()
+   {
+      this.randomFile = null;
 
-      return digest;
+      if (this.randomIS != null)
+      {
+         try
+         {
+            this.randomIS.close();
+         }
+         catch (Exception e)
+         {
+            log.warn("Failed to close randomIS.");
+         }
+
+         this.randomIS = null;
+      }
    }
 
 }




More information about the jboss-cvs-commits mailing list