Author: remy.maucherat(a)jboss.com
Date: 2010-11-19 11:06:19 -0500 (Fri, 19 Nov 2010)
New Revision: 1579
Modified:
trunk/java/org/apache/catalina/Manager.java
trunk/java/org/apache/catalina/Service.java
trunk/java/org/apache/catalina/authenticator/AuthenticatorBase.java
trunk/java/org/apache/catalina/connector/Request.java
trunk/java/org/apache/catalina/core/ApplicationHttpRequest.java
trunk/java/org/apache/catalina/core/StandardService.java
trunk/java/org/apache/catalina/session/ManagerBase.java
trunk/java/org/apache/catalina/session/PersistentManagerBase.java
trunk/java/org/apache/catalina/session/StandardManager.java
trunk/java/org/apache/tomcat/util/net/AprEndpoint.java
trunk/webapps/docs/changelog.xml
Log:
- Improve session id creation.
- Add a master SecureRandom in Service.
- Add local SecureRandom providers seeded with the master SecureRandom in the Request.
- Port session id hashing and alphabet from AS 6 (which will need a little refactoring).
Modified: trunk/java/org/apache/catalina/Manager.java
===================================================================
--- trunk/java/org/apache/catalina/Manager.java 2010-11-10 05:25:41 UTC (rev 1578)
+++ trunk/java/org/apache/catalina/Manager.java 2010-11-19 16:06:19 UTC (rev 1579)
@@ -21,6 +21,7 @@
import java.beans.PropertyChangeListener;
import java.io.IOException;
+import java.util.Random;
/**
@@ -265,7 +266,7 @@
*
* @param session The session to change the session ID for
*/
- public void changeSessionId(Session session);
+ public void changeSessionId(Session session, Random random);
/**
@@ -279,20 +280,6 @@
/**
* Construct and return a new session object, based on the default
* settings specified by this Manager's properties. The session
- * id will be assigned by this method, and available via the getId()
- * method of the returned session. If a new session cannot be created
- * for any reason, return <code>null</code>.
- *
- * @exception IllegalStateException if a new session cannot be
- * instantiated for any reason
- * @deprecated
- */
- public Session createSession();
-
-
- /**
- * Construct and return a new session object, based on the default
- * settings specified by this Manager's properties. The session
* id specified will be used as the session id.
* If a new session cannot be created for any reason, return
* <code>null</code>.
@@ -304,7 +291,7 @@
* @exception IllegalStateException if a new session cannot be
* instantiated for any reason
*/
- public Session createSession(String sessionId);
+ public Session createSession(String sessionId, Random random);
/**
Modified: trunk/java/org/apache/catalina/Service.java
===================================================================
--- trunk/java/org/apache/catalina/Service.java 2010-11-10 05:25:41 UTC (rev 1578)
+++ trunk/java/org/apache/catalina/Service.java 2010-11-19 16:06:19 UTC (rev 1579)
@@ -18,6 +18,8 @@
package org.apache.catalina;
+import java.security.SecureRandom;
+
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.http.mapper.Mapper;
@@ -80,6 +82,19 @@
public void setName(String name);
/**
+ * Return the entropy increaser value, or compute a semi-useful value
+ * if this String has not yet been set.
+ */
+ public String getEntropy();
+
+ /**
+ * Set the entropy increaser value.
+ *
+ * @param entropy The new entropy increaser value
+ */
+ public void setEntropy(String entropy);
+
+ /**
* Return the <code>Server</code> with which we are associated (if any).
*/
public Server getServer();
@@ -149,4 +164,9 @@
*/
public void removeExecutor(Executor ex);
+ /**
+ * Get the global secure random that will be used for this service.
+ */
+ public SecureRandom getRandom();
+
}
Modified: trunk/java/org/apache/catalina/authenticator/AuthenticatorBase.java
===================================================================
--- trunk/java/org/apache/catalina/authenticator/AuthenticatorBase.java 2010-11-10
05:25:41 UTC (rev 1578)
+++ trunk/java/org/apache/catalina/authenticator/AuthenticatorBase.java 2010-11-19
16:06:19 UTC (rev 1579)
@@ -784,7 +784,7 @@
Session session = request.getSessionInternal(false);
if (session != null && changeSessionIdOnAuthentication) {
Manager manager = request.getContext().getManager();
- manager.changeSessionId(session);
+ manager.changeSessionId(session, request.getRandom());
request.changeSessionId(session.getId());
}
// Cache the authentication information in our session, if any
Modified: trunk/java/org/apache/catalina/connector/Request.java
===================================================================
--- trunk/java/org/apache/catalina/connector/Request.java 2010-11-10 05:25:41 UTC (rev
1578)
+++ trunk/java/org/apache/catalina/connector/Request.java 2010-11-19 16:06:19 UTC (rev
1579)
@@ -53,6 +53,7 @@
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.Principal;
+import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -64,6 +65,7 @@
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
+import java.util.Random;
import java.util.TimeZone;
import java.util.TreeMap;
@@ -168,7 +170,7 @@
formats[0].setTimeZone(GMT_ZONE);
formats[1].setTimeZone(GMT_ZONE);
formats[2].setTimeZone(GMT_ZONE);
-
+
}
@@ -479,6 +481,12 @@
protected boolean sslAttributes = false;
+ /**
+ * Random generator.
+ */
+ protected Random random = null;
+
+
// --------------------------------------------------------- Public Methods
@@ -622,6 +630,10 @@
*/
public void setConnector(Connector connector) {
this.connector = connector;
+ SecureRandom seedRandom = connector.getService().getRandom();
+ synchronized (seedRandom) {
+ random = new SecureRandom(seedRandom.generateSeed(16));
+ }
}
@@ -652,6 +664,13 @@
/**
+ * Return the Random.
+ */
+ public Random getRandom() {
+ return (this.random);
+ }
+
+ /**
* Filter chains associated with the request.
*/
protected ArrayList<ApplicationFilterChain> filterChains = new
ArrayList<ApplicationFilterChain>();
@@ -2603,7 +2622,7 @@
sessionId = null;
}
}
- session = manager.createSession(sessionId);
+ session = manager.createSession(sessionId, random);
// Creating a new session cookie based on that session
// If there was no cookie with the current session id, add a cookie to the
response
Modified: trunk/java/org/apache/catalina/core/ApplicationHttpRequest.java
===================================================================
--- trunk/java/org/apache/catalina/core/ApplicationHttpRequest.java 2010-11-10 05:25:41
UTC (rev 1578)
+++ trunk/java/org/apache/catalina/core/ApplicationHttpRequest.java 2010-11-19 16:06:19
UTC (rev 1579)
@@ -556,7 +556,7 @@
localSession = null;
if (localSession == null && create) {
localSession =
- context.getManager().createSession(other.getId());
+ context.getManager().createSession(other.getId(), null);
}
if (localSession != null) {
localSession.access();
Modified: trunk/java/org/apache/catalina/core/StandardService.java
===================================================================
--- trunk/java/org/apache/catalina/core/StandardService.java 2010-11-10 05:25:41 UTC (rev
1578)
+++ trunk/java/org/apache/catalina/core/StandardService.java 2010-11-19 16:06:19 UTC (rev
1579)
@@ -21,6 +21,8 @@
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
+import java.lang.reflect.Method;
+import java.security.SecureRandom;
import java.util.ArrayList;
import javax.management.MBeanRegistration;
@@ -36,6 +38,7 @@
import org.apache.catalina.Server;
import org.apache.catalina.Service;
import org.apache.catalina.connector.Connector;
+import org.apache.catalina.util.Base64;
import org.apache.catalina.util.LifecycleSupport;
import org.apache.catalina.util.StringManager;
import org.apache.tomcat.util.http.mapper.Mapper;
@@ -145,6 +148,19 @@
protected boolean initialized = false;
+ /**
+ * A String initialization parameter used to increase the entropy of
+ * the initialization of our random number generator.
+ */
+ protected String entropy = null;
+
+
+ /**
+ * The random associated with this service.
+ */
+ protected SecureRandom random = null;
+
+
// ------------------------------------------------------------- Properties
@@ -269,9 +285,53 @@
}
+ @Override
+ public String getEntropy() {
+ // Calculate a semi-useful value if this has not been set
+ if (this.entropy == null) {
+ // Use APR to get a crypto secure entropy value
+ byte[] result = new byte[32];
+ boolean apr = false;
+ try {
+ String methodName = "random";
+ Class paramTypes[] = new Class[2];
+ paramTypes[0] = result.getClass();
+ paramTypes[1] = int.class;
+ Object paramValues[] = new Object[2];
+ paramValues[0] = result;
+ paramValues[1] = new Integer(32);
+ Method method = Class.forName("org.apache.tomcat.jni.OS")
+ .getMethod(methodName, paramTypes);
+ method.invoke(null, paramValues);
+ apr = true;
+ } catch (Throwable t) {
+ // Ignore
+ }
+ if (apr) {
+ setEntropy(new String(Base64.encode(result)));
+ } else {
+ setEntropy(this.toString());
+ }
+ }
+ return (this.entropy);
+ }
+
+
+ @Override
+ public void setEntropy(String entropy) {
+ this.entropy = entropy;
+ }
+
+
// --------------------------------------------------------- Public Methods
+ @Override
+ public SecureRandom getRandom() {
+ return random;
+ }
+
+
/**
* Add a new Connector to the set of defined Connectors, and associate it
* with this Service's Container.
@@ -697,10 +757,13 @@
// Initialize our defined Connectors
synchronized (connectors) {
- for (int i = 0; i < connectors.length; i++) {
- connectors[i].initialize();
- }
+ for (int i = 0; i < connectors.length; i++) {
+ connectors[i].initialize();
+ }
}
+
+ // Construct and seed a new random number generator
+ random = new SecureRandom(getEntropy().getBytes());
}
public void destroy() throws LifecycleException {
@@ -749,4 +812,5 @@
public void postDeregister() {
}
+
}
Modified: trunk/java/org/apache/catalina/session/ManagerBase.java
===================================================================
--- trunk/java/org/apache/catalina/session/ManagerBase.java 2010-11-10 05:25:41 UTC (rev
1578)
+++ trunk/java/org/apache/catalina/session/ManagerBase.java 2010-11-19 16:06:19 UTC (rev
1579)
@@ -21,15 +21,7 @@
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
-import java.io.DataInputStream;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
-import java.lang.reflect.Method;
-import java.security.AccessController;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivilegedAction;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
@@ -44,16 +36,13 @@
import org.apache.catalina.Container;
import org.apache.catalina.Engine;
-import org.apache.catalina.Globals;
import org.apache.catalina.Manager;
import org.apache.catalina.Session;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardHost;
-import org.apache.catalina.util.Base64;
import org.apache.catalina.util.StringManager;
import org.apache.tomcat.util.modeler.Registry;
import org.jboss.logging.Logger;
-import org.jboss.logging.Logger;
/**
@@ -68,40 +57,19 @@
public abstract class ManagerBase implements Manager, MBeanRegistration {
protected Logger log = Logger.getLogger(ManagerBase.class);
- // ----------------------------------------------------- Instance Variables
+ private static final char[] SESSION_ID_ALPHABET =
+
System.getProperty("org.apache.catalina.session.ManagerBase.SESSION_ID_ALPHABET",
+
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-_").toCharArray();
+
+ // ----------------------------------------------------- Instance Variables
- protected DataInputStream randomIS=null;
- protected String devRandomSource="/dev/urandom";
-
/**
- * The default message digest algorithm to use if we cannot use
- * the requested one.
- */
- protected static final String DEFAULT_ALGORITHM = "MD5";
-
-
- /**
- * The message digest algorithm to be used when generating session
- * identifiers. This must be an algorithm supported by the
- * <code>java.security.MessageDigest</code> class on your platform.
- */
- protected String algorithm = DEFAULT_ALGORITHM;
-
-
- /**
* The Container with which this Manager is associated.
*/
protected Container container;
/**
- * Return the MessageDigest implementation to be used when
- * creating session identifiers.
- */
- protected MessageDigest digest = null;
-
-
- /**
* The distributable flag for Sessions created by this Manager. If this
* flag is set to <code>true</code>, any user attributes added to a
* session controlled by this Manager must be Serializable.
@@ -110,16 +78,9 @@
/**
- * A String initialization parameter used to increase the entropy of
- * the initialization of our random number generator.
- */
- protected String entropy = null;
-
-
- /**
* The descriptive information string for this implementation.
*/
- private static final String info = "ManagerBase/1.0";
+ private static final String info = "ManagerBase/2.0";
/**
@@ -132,7 +93,7 @@
/**
* The session id length of Sessions created by this Manager.
*/
- protected int sessionIdLength = 16;
+ protected int sessionIdLength = 18;
/**
@@ -142,19 +103,6 @@
/**
- * A random number generator to use when generating session identifiers.
- */
- protected Random random = null;
-
-
- /**
- * The Java class name of the random number generator class to be used
- * when generating session identifiers.
- */
- protected String randomClass = "java.security.SecureRandom";
-
-
- /**
* The longest time (in seconds) that an expired session had been alive.
*/
protected int sessionMaxAliveTime;
@@ -219,68 +167,9 @@
protected PropertyChangeSupport support = new PropertyChangeSupport(this);
- // ------------------------------------------------------------- Security classes
-
-
- private class PrivilegedSetRandomFile implements
PrivilegedAction<DataInputStream>{
-
- public PrivilegedSetRandomFile(String s) {
- devRandomSource = s;
- }
-
- public DataInputStream run(){
- try {
- File f=new File( devRandomSource );
- if( ! f.exists() ) return null;
- randomIS= new DataInputStream( new FileInputStream(f));
- randomIS.readLong();
- if( log.isDebugEnabled() )
- log.debug( "Opening " + devRandomSource );
- return randomIS;
- } catch (IOException ex){
- log.warn("Error reading " + devRandomSource, ex);
- if (randomIS != null) {
- try {
- randomIS.close();
- } catch (Exception e) {
- log.warn("Failed to close randomIS.");
- }
- }
- devRandomSource = null;
- randomIS=null;
- return null;
- }
- }
- }
-
-
// ------------------------------------------------------------- Properties
/**
- * Return the message digest algorithm for this Manager.
- */
- public String getAlgorithm() {
-
- return (this.algorithm);
-
- }
-
-
- /**
- * Set the message digest algorithm for this Manager.
- *
- * @param algorithm The new message digest algorithm
- */
- public void setAlgorithm(String algorithm) {
-
- String oldAlgorithm = this.algorithm;
- this.algorithm = algorithm;
- support.firePropertyChange("algorithm", oldAlgorithm, this.algorithm);
-
- }
-
-
- /**
* Return the Container with which this Manager is associated.
*/
public Container getContainer() {
@@ -311,41 +200,6 @@
/**
- * Return the MessageDigest object to be used for calculating
- * session identifiers. If none has been created yet, initialize
- * one the first time this method is called.
- */
- public synchronized MessageDigest getDigest() {
-
- if (this.digest == null) {
- long t1=System.currentTimeMillis();
- if (log.isDebugEnabled())
- log.debug(sm.getString("managerBase.getting", algorithm));
- try {
- this.digest = MessageDigest.getInstance(algorithm);
- } catch (NoSuchAlgorithmException e) {
- log.error(sm.getString("managerBase.digest", algorithm), e);
- try {
- this.digest = MessageDigest.getInstance(DEFAULT_ALGORITHM);
- } catch (NoSuchAlgorithmException f) {
- log.error(sm.getString("managerBase.digest",
- DEFAULT_ALGORITHM), e);
- this.digest = null;
- }
- }
- if (log.isDebugEnabled())
- log.debug(sm.getString("managerBase.gotten"));
- long t2=System.currentTimeMillis();
- if( log.isDebugEnabled() )
- log.debug("getDigest() " + (t2-t1));
- }
-
- return (this.digest);
-
- }
-
-
- /**
* Return the distributable flag for the sessions supported by
* this Manager.
*/
@@ -375,58 +229,6 @@
/**
- * Return the entropy increaser value, or compute a semi-useful value
- * if this String has not yet been set.
- */
- public String getEntropy() {
-
- // Calculate a semi-useful value if this has not been set
- if (this.entropy == null) {
- // Use APR to get a crypto secure entropy value
- byte[] result = new byte[32];
- boolean apr = false;
- try {
- String methodName = "random";
- Class paramTypes[] = new Class[2];
- paramTypes[0] = result.getClass();
- paramTypes[1] = int.class;
- Object paramValues[] = new Object[2];
- paramValues[0] = result;
- paramValues[1] = new Integer(32);
- Method method = Class.forName("org.apache.tomcat.jni.OS")
- .getMethod(methodName, paramTypes);
- method.invoke(null, paramValues);
- apr = true;
- } catch (Throwable t) {
- // Ignore
- }
- if (apr) {
- setEntropy(new String(Base64.encode(result)));
- } else {
- setEntropy(this.toString());
- }
- }
-
- return (this.entropy);
-
- }
-
-
- /**
- * Set the entropy increaser value.
- *
- * @param entropy The new entropy increaser value
- */
- public void setEntropy(String entropy) {
-
- String oldEntropy = entropy;
- this.entropy = entropy;
- support.firePropertyChange("entropy", oldEntropy, this.entropy);
-
- }
-
-
- /**
* Return descriptive information about this Manager implementation and
* the corresponding version number, in the format
* <code><description>/<version></code>.
@@ -505,110 +307,7 @@
}
- /**
- * Use /dev/random-type special device. This is new code, but may reduce
- * the big delay in generating the random.
- *
- * You must specify a path to a random generator file. Use /dev/urandom
- * for linux ( or similar ) systems. Use /dev/random for maximum security
- * ( it may block if not enough "random" exist ). You can also use
- * a pipe that generates random.
- *
- * The code will check if the file exists, and default to java Random
- * if not found. There is a significant performance difference, very
- * visible on the first call to getSession ( like in the first JSP )
- * - so use it if available.
- */
- public void setRandomFile( String s ) {
- // as a hack, you can use a static file - and generate the same
- // session ids ( good for strange debugging )
- if (Globals.IS_SECURITY_ENABLED){
- randomIS = AccessController.doPrivileged(new PrivilegedSetRandomFile(s));
- } else {
- try{
- devRandomSource=s;
- File f=new File( devRandomSource );
- if( ! f.exists() ) return;
- randomIS= new DataInputStream( new FileInputStream(f));
- randomIS.readLong();
- if( log.isDebugEnabled() )
- log.debug( "Opening " + devRandomSource );
- } catch( IOException ex ) {
- log.warn("Error reading " + devRandomSource, ex);
- if (randomIS != null) {
- try {
- randomIS.close();
- } catch (Exception e) {
- log.warn("Failed to close randomIS.");
- }
- }
- devRandomSource = null;
- randomIS=null;
- }
- }
- }
-
- public String getRandomFile() {
- return devRandomSource;
- }
-
-
/**
- * Return the random number generator instance we should use for
- * generating session identifiers. If there is no such generator
- * currently defined, construct and seed a new one.
- */
- public Random getRandom() {
- if (this.random == null) {
- // Calculate the new random number generator seed
- 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;
- }
- // Construct and seed a new random number generator
- try {
- Class clazz = Class.forName(randomClass);
- this.random = (Random) clazz.newInstance();
- } catch (Exception e) {
- log.warn(sm.getString("managerBase.random", randomClass), e);
- this.random = new java.util.Random();
- }
- this.random.setSeed(seed);
- }
-
- return (this.random);
-
- }
-
-
- /**
- * Return the random number generator class name.
- */
- public String getRandomClass() {
-
- return (this.randomClass);
-
- }
-
-
- /**
- * Set the random number generator class name.
- *
- * @param randomClass The new random number generator class name
- */
- public void setRandomClass(String randomClass) {
-
- String oldRandomClass = this.randomClass;
- this.randomClass = randomClass;
- support.firePropertyChange("randomClass", oldRandomClass,
- this.randomClass);
-
- }
-
-
- /**
* Gets the number of sessions that have expired.
*
* @return Number of sessions that have expired
@@ -702,14 +401,6 @@
public void destroy() {
if( oname != null )
Registry.getRegistry(null, null).unregisterComponent(oname);
- if (randomIS!=null) {
- try {
- randomIS.close();
- } catch (IOException ioe) {
- log.warn("Failed to close randomIS.");
- }
- randomIS=null;
- }
initialized=false;
oname = null;
}
@@ -739,9 +430,6 @@
}
}
- // Initialize random number generation
- getRandomBytes(new byte[16]);
-
if(log.isDebugEnabled())
log.debug("Registering " + oname );
@@ -780,30 +468,14 @@
*
* @param session The session to change the session ID for
*/
- public void changeSessionId(Session session) {
- session.setId(generateSessionId());
+ public void changeSessionId(Session session, Random random) {
+ session.setId(generateSessionId(random));
}
/**
* Construct and return a new session object, based on the default
* settings specified by this Manager's properties. The session
- * id will be assigned by this method, and available via the getId()
- * method of the returned session. If a new session cannot be created
- * for any reason, return <code>null</code>.
- *
- * @exception IllegalStateException if a new session cannot be
- * instantiated for any reason
- * @deprecated
- */
- public Session createSession() {
- return createSession(null);
- }
-
-
- /**
- * Construct and return a new session object, based on the default
- * settings specified by this Manager's properties. The session
* id specified will be used as the session id.
* If a new session cannot be created for any reason, return
* <code>null</code>.
@@ -814,7 +486,7 @@
* @exception IllegalStateException if a new session cannot be
* instantiated for any reason
*/
- public Session createSession(String sessionId) {
+ public Session createSession(String sessionId, Random random) {
// Recycle or create a Session instance
Session session = createEmptySession();
@@ -825,34 +497,7 @@
session.setCreationTime(System.currentTimeMillis());
session.setMaxInactiveInterval(this.maxInactiveInterval);
if (sessionId == null) {
- sessionId = generateSessionId();
- // FIXME WHy we need no duplication check?
- /*
- synchronized (sessions) {
- while (sessions.get(sessionId) != null) { // Guarantee
- // uniqueness
- duplicates++;
- sessionId = generateSessionId();
- }
- }
- */
-
- // FIXME: Code to be used in case route replacement is needed
- /*
- } else {
- String jvmRoute = getJvmRoute();
- if (getJvmRoute() != null) {
- String requestJvmRoute = null;
- int index = sessionId.indexOf(".");
- if (index > 0) {
- requestJvmRoute = sessionId
- .substring(index + 1, sessionId.length());
- }
- if (requestJvmRoute != null && !requestJvmRoute.equals(jvmRoute))
{
- sessionId = sessionId.substring(0, index) + "." +
jvmRoute;
- }
- }
- */
+ sessionId = generateSessionId(random);
}
session.setId(sessionId);
sessionCounter++;
@@ -938,83 +583,70 @@
}
- protected void getRandomBytes(byte bytes[]) {
- // Generate a byte array containing a session identifier
- if (devRandomSource != null && randomIS == null) {
- setRandomFile(devRandomSource);
+ /**
+ * Generate and return a new session identifier.
+ */
+ protected String generateSessionId(Random random) {
+ byte[] bytes = new byte[sessionIdLength];
+ random.nextBytes(bytes);
+ // Encode the result
+ char[] id = encode(bytes);
+ String jvmRoute = getJvmRoute();
+ if (appendJVMRoute() && jvmRoute != null) {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append(id).append('.').append(jvmRoute);
+ return buffer.toString();
+ } else {
+ return String.valueOf(id);
}
- if (randomIS != null) {
- try {
- int len = randomIS.read(bytes);
- if (len == bytes.length) {
- return;
- }
- if(log.isDebugEnabled())
- log.debug("Got " + len + " " + bytes.length );
- } catch (Exception ex) {
- // Ignore
- }
- devRandomSource = null;
-
- try {
- randomIS.close();
- } catch (Exception e) {
- log.warn("Failed to close randomIS.");
- }
-
- randomIS = null;
- }
- getRandom().nextBytes(bytes);
}
-
+ protected boolean appendJVMRoute() {
+ return true;
+ }
+
/**
- * Generate and return a new session identifier.
+ * Encode the bytes into a String with a slightly modified Base64-algorithm
+ * This code was written by Kevin Kelley <kelley(a)ruralnet.net>
+ * and adapted by Thomas Peuss <jboss(a)peuss.de>
+ *
+ * @param data The bytes you want to encode
+ * @return the encoded String
*/
- protected synchronized String generateSessionId() {
+ protected static char[] encode(byte[] data) {
+ char[] out = new char[((data.length + 2) / 3) * 4];
+ char[] alphabet = SESSION_ID_ALPHABET;
+ //
+ // 3 bytes encode to 4 chars. Output is always an even
+ // multiple of 4 characters.
+ //
+ for (int i = 0, index = 0; i < data.length; i += 3, index += 4) {
+ boolean quad = false;
+ boolean trip = false;
- byte random[] = new byte[16];
- String jvmRoute = getJvmRoute();
- String result = null;
-
- // Render the result as a String of hexadecimal digits
- StringBuilder buffer = new StringBuilder();
- do {
- int resultLenBytes = 0;
- if (result != null) {
- buffer = new StringBuilder();
- duplicates++;
- }
-
- while (resultLenBytes < this.sessionIdLength) {
- getRandomBytes(random);
- random = getDigest().digest(random);
- for (int j = 0;
- j < random.length && resultLenBytes <
this.sessionIdLength;
- j++) {
- byte b1 = (byte) ((random[j] & 0xf0) >> 4);
- byte b2 = (byte) (random[j] & 0x0f);
- if (b1 < 10)
- buffer.append((char) ('0' + b1));
- else
- buffer.append((char) ('A' + (b1 - 10)));
- if (b2 < 10)
- buffer.append((char) ('0' + b2));
- else
- buffer.append((char) ('A' + (b2 - 10)));
- resultLenBytes++;
- }
- }
- if (jvmRoute != null) {
- buffer.append('.').append(jvmRoute);
- }
- result = buffer.toString();
- } while (sessions.containsKey(result));
- return (result);
-
+ int val = (0xFF & (int) data[i]);
+ val <<= 8;
+ if ((i + 1) < data.length) {
+ val |= (0xFF & (int) data[i + 1]);
+ trip = true;
+ }
+ val <<= 8;
+ if ((i + 2) < data.length) {
+ val |= (0xFF & (int) data[i + 2]);
+ quad = true;
+ }
+ out[index + 3] = alphabet[(quad ? (val & 0x3F) : 64)];
+ val >>= 6;
+ out[index + 2] = alphabet[(trip ? (val & 0x3F) : 64)];
+ val >>= 6;
+ out[index + 1] = alphabet[val & 0x3F];
+ val >>= 6;
+ out[index + 0] = alphabet[val & 0x3F];
+ }
+ return out;
}
-
+
// ------------------------------------------------------ Protected Methods
Modified: trunk/java/org/apache/catalina/session/PersistentManagerBase.java
===================================================================
--- trunk/java/org/apache/catalina/session/PersistentManagerBase.java 2010-11-10 05:25:41
UTC (rev 1578)
+++ trunk/java/org/apache/catalina/session/PersistentManagerBase.java 2010-11-19 16:06:19
UTC (rev 1579)
@@ -34,11 +34,9 @@
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.Session;
import org.apache.catalina.Store;
-import org.apache.catalina.util.LifecycleSupport;
-
import org.apache.catalina.security.SecurityUtil;
+import org.apache.catalina.util.LifecycleSupport;
import org.jboss.logging.Logger;
-import org.jboss.logging.Logger;
/**
* Extends the <b>ManagerBase</b> class to implement most of the
* functionality required by a Manager which supports any kind of
@@ -983,13 +981,6 @@
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true;
- // Force initialization of the random number generator
- if (log.isDebugEnabled())
- log.debug("Force random number initialization starting");
- String dummy = generateSessionId();
- if (log.isDebugEnabled())
- log.debug("Force random number initialization completed");
-
if (store == null)
log.error("No Store configured, persistence disabled");
else if (store instanceof Lifecycle)
@@ -1036,9 +1027,6 @@
if (getStore() != null && getStore() instanceof Lifecycle)
((Lifecycle)getStore()).stop();
- // Require a new random number generator if we are restarted
- this.random = null;
-
if( initialized )
destroy();
Modified: trunk/java/org/apache/catalina/session/StandardManager.java
===================================================================
--- trunk/java/org/apache/catalina/session/StandardManager.java 2010-11-10 05:25:41 UTC
(rev 1578)
+++ trunk/java/org/apache/catalina/session/StandardManager.java 2010-11-19 16:06:19 UTC
(rev 1579)
@@ -34,6 +34,7 @@
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Iterator;
+import java.util.Random;
import javax.servlet.ServletContext;
@@ -279,7 +280,7 @@
* @exception IllegalStateException if a new session cannot be
* instantiated for any reason
*/
- public Session createSession(String sessionId) {
+ public Session createSession(String sessionId, Random random) {
if ((maxActiveSessions >= 0) &&
(sessions.size() >= maxActiveSessions)) {
@@ -288,7 +289,7 @@
(sm.getString("standardManager.createSession.ise"));
}
- return (super.createSession(sessionId));
+ return (super.createSession(sessionId, random));
}
@@ -627,13 +628,6 @@
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true;
- // Force initialization of the random number generator
- if (log.isDebugEnabled())
- log.debug("Force random number initialization starting");
- String dummy = generateSessionId();
- if (log.isDebugEnabled())
- log.debug("Force random number initialization completed");
-
// Load unloaded sessions, if any
try {
load();
@@ -685,9 +679,6 @@
}
}
- // Require a new random number generator if we are restarted
- this.random = null;
-
if( initialized ) {
destroy();
}
Modified: trunk/java/org/apache/tomcat/util/net/AprEndpoint.java
===================================================================
--- trunk/java/org/apache/tomcat/util/net/AprEndpoint.java 2010-11-10 05:25:41 UTC (rev
1578)
+++ trunk/java/org/apache/tomcat/util/net/AprEndpoint.java 2010-11-19 16:06:19 UTC (rev
1579)
@@ -186,7 +186,7 @@
/**
* Size of the socket poller.
*/
- protected int pollerSize = (OS.IS_WIN32 || OS.IS_WIN64) ? (8 * 1024) : (32 * 1024);
+ protected int pollerSize = -1;
public void setPollerSize(int pollerSize) { this.pollerSize = pollerSize; }
public int getPollerSize() { return pollerSize; }
@@ -194,7 +194,7 @@
/**
* Size of the sendfile (= concurrent files which can be served).
*/
- protected int sendfileSize = (OS.IS_WIN32 || OS.IS_WIN64) ? (1 * 1024) : (16 *
1024);
+ protected int sendfileSize = -1;
public void setSendfileSize(int sendfileSize) { this.sendfileSize = sendfileSize; }
public int getSendfileSize() { return sendfileSize; }
@@ -582,6 +582,14 @@
useSendfile = false;
}
+ // Poller size defaults
+ if (pollerSize <= 0) {
+ pollerSize = (OS.IS_WIN32 || OS.IS_WIN64) ? (8 * 1024) : (32 * 1024);
+ }
+ if (sendfileSize <= 0) {
+ sendfileSize = (OS.IS_WIN32 || OS.IS_WIN64) ? (1 * 1024) : (16 * 1024);
+ }
+
long inetAddress = Address.info(addressStr, family,
port, 0, rootPool);
Modified: trunk/webapps/docs/changelog.xml
===================================================================
--- trunk/webapps/docs/changelog.xml 2010-11-10 05:25:41 UTC (rev 1578)
+++ trunk/webapps/docs/changelog.xml 2010-11-19 16:06:19 UTC (rev 1579)
@@ -25,6 +25,9 @@
<fix>
<jira>189</jira>: Overlay timestamps need special treatment. (remm)
</fix>
+ <fix>
+ Improve session id creation. (remm)
+ </fix>
</changelog>
</subsection>
<subsection name="Jasper">