[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