From: markt
Date: Tue, 30 Nov 2010 13:15:51 +0000 (+0000)
Subject: Remove direct support for reading random bytes from a file
X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=7d653cf1c6d234cc7283dbd67535d918e7ea2548;p=tomcat7.0
Remove direct support for reading random bytes from a file
Add support for specifying SecureRandom algorithm and provider
git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1040511 13f79535-47bb-0310-9956-ffa450edef68
---
diff --git a/java/org/apache/catalina/ha/session/BackupManager.java b/java/org/apache/catalina/ha/session/BackupManager.java
index a077230d5..316cac595 100644
--- a/java/org/apache/catalina/ha/session/BackupManager.java
+++ b/java/org/apache/catalina/ha/session/BackupManager.java
@@ -202,7 +202,6 @@ public class BackupManager extends ClusterManagerBase
}
cluster.removeManager(this);
- this.randoms.clear();
super.stopInternal();
}
diff --git a/java/org/apache/catalina/ha/session/DeltaManager.java b/java/org/apache/catalina/ha/session/DeltaManager.java
index ce738e400..3bdc8b0cd 100644
--- a/java/org/apache/catalina/ha/session/DeltaManager.java
+++ b/java/org/apache/catalina/ha/session/DeltaManager.java
@@ -961,7 +961,6 @@ public CatalinaCluster getCluster() {
// Require a new random number generator if we are restarted
getCluster().removeManager(this);
- this.randoms.clear();
super.stopInternal();
replicationValve = null;
}
diff --git a/java/org/apache/catalina/session/LocalStrings.properties b/java/org/apache/catalina/session/LocalStrings.properties
index a3deb7146..a25967a49 100644
--- a/java/org/apache/catalina/session/LocalStrings.properties
+++ b/java/org/apache/catalina/session/LocalStrings.properties
@@ -28,12 +28,10 @@ JDBCStore.checkConnectionDBReOpenFail=The re-open on the database failed. The da
JDBCStore.checkConnectionSQLException=A SQL exception occurred {0}
JDBCStore.checkConnectionClassNotFoundException=JDBC driver class not found {0}
managerBase.createRandom=Created random number generator for session ID generation in {0}ms.
-managerBase.createRandomSeed=Created SecureRandom instance to seed random number generators for session ID generation in {0}ms.
managerBase.createSession.ise=createSession: Too many active sessions
-managerBase.getting=Getting message digest component for algorithm {0}
-managerBase.gotten=Completed getting message digest component
-managerBase.random=Exception initializing random number generator of class {0}. Falling back to java.util.Random.
-managerBase.seedFailed=Failed to seed random number generator class {0}
+managerBase.random=Exception initializing random number generator of class [{0}]. Falling back to java.secure.SecureRandom
+managerBase.randomAlgorithm=Exception initializing random number generator using algorithm [{0}]
+managerBase.randomProviderException initializing random number generator using provider [{0}]
managerBase.sessionTimeout=Invalid session timeout setting {0}
serverSession.value.iae=null value
standardManager.expireException=processsExpire: Exception during session expiration
diff --git a/java/org/apache/catalina/session/LocalStrings_es.properties b/java/org/apache/catalina/session/LocalStrings_es.properties
index 0aa6ca8a4..6b078c223 100644
--- a/java/org/apache/catalina/session/LocalStrings_es.properties
+++ b/java/org/apache/catalina/session/LocalStrings_es.properties
@@ -27,8 +27,6 @@ JDBCStore.checkConnectionDBReOpenFail = Fall\u00F3 la reapertura de la base de d
JDBCStore.checkConnectionSQLException = Ha tenido lugar una excepci\u00F3n SQL {0}
JDBCStore.checkConnectionClassNotFoundException = No se ha hallado la clase del manejador (driver) JDBC {0}
managerBase.createSession.ise = createSession\: Demasiadas sesiones activas
-managerBase.getting = Obteniendo mensaje de componente de resumen (digest) para algoritmo {0}
-managerBase.gotten = Completada la obtenci\u00F3n de mensaje de componente de resumen (digest)
managerBase.random = Excepci\u00F3n inicializando generador de n\u00FAmeros aleatorios de clase {0}
managerBase.sessionTimeout = Valor inv\u00E1lido de Tiempo Agotado de sesi\u00F3n {0}
serverSession.value.iae = valor nulo
diff --git a/java/org/apache/catalina/session/LocalStrings_fr.properties b/java/org/apache/catalina/session/LocalStrings_fr.properties
index 82a80cd4f..ff96f5112 100644
--- a/java/org/apache/catalina/session/LocalStrings_fr.properties
+++ b/java/org/apache/catalina/session/LocalStrings_fr.properties
@@ -27,8 +27,6 @@ JDBCStore.checkConnectionDBReOpenFail=La tentative de r\u00e9ouverture de la bas
JDBCStore.checkConnectionSQLException=Une exception SQL s''est produite {0}
JDBCStore.checkConnectionClassNotFoundException=La classe du driver JDBC n''a pas \u00e9t\u00e9 trouv\u00e9e {0}
managerBase.createSession.ise="createSession": Trop de sessions actives
-managerBase.getting=Prise du composant d''algorithme empreinte de message (message digest) pour l''algorithme {0}
-managerBase.gotten=Prise du composant d''algorithme empreinte de message (message digest) termin\u00e9e
managerBase.random=Exception durant l''initialisation de la classe du g\u00e9n\u00e9rateur de nombre al\u00e9atoire {0}
managerBase.sessionTimeout=R\u00e9glage du d\u00e9lai d''inactivit\u00e9 (timeout) de session invalide {0}
serverSession.value.iae=valeur nulle
diff --git a/java/org/apache/catalina/session/LocalStrings_ja.properties b/java/org/apache/catalina/session/LocalStrings_ja.properties
index 5e98862a7..b4d08b9f4 100644
--- a/java/org/apache/catalina/session/LocalStrings_ja.properties
+++ b/java/org/apache/catalina/session/LocalStrings_ja.properties
@@ -28,8 +28,6 @@ JDBCStore.checkConnectionDBReOpenFail=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e
JDBCStore.checkConnectionSQLException=SQL\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f {0}
JDBCStore.checkConnectionClassNotFoundException=JDBC\u30c9\u30e9\u30a4\u30d0\u30af\u30e9\u30b9\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 {0}
managerBase.createSession.ise=createSession: \u30a2\u30af\u30c6\u30a3\u30d6\u30bb\u30c3\u30b7\u30e7\u30f3\u304c\u591a\u3059\u304e\u307e\u3059
-managerBase.getting=\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0 {0} \u306e\u30e1\u30c3\u30bb\u30fc\u30b8\u30c0\u30a4\u30b8\u30a7\u30b9\u30c8\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u3092\u53d6\u5f97\u3057\u307e\u3059
-managerBase.gotten=\u30e1\u30c3\u30bb\u30fc\u30b8\u30c0\u30a4\u30b8\u30a7\u30b9\u30c8\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u306e\u53d6\u5f97\u3092\u5b8c\u4e86\u3057\u307e\u3057\u305f
managerBase.random=\u30af\u30e9\u30b9 {0} \u306e\u4e71\u6570\u767a\u751f\u5668\u306e\u521d\u671f\u5316\u306e\u4f8b\u5916\u3067\u3059
managerBase.sessionTimeout=\u7121\u52b9\u306a\u30bb\u30c3\u30b7\u30e7\u30f3\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u8a2d\u5b9a\u3067\u3059 {0}
serverSession.value.iae=null\u5024\u3067\u3059
diff --git a/java/org/apache/catalina/session/ManagerBase.java b/java/org/apache/catalina/session/ManagerBase.java
index a64a9ce87..69dee73e4 100644
--- a/java/org/apache/catalina/session/ManagerBase.java
+++ b/java/org/apache/catalina/session/ManagerBase.java
@@ -22,12 +22,9 @@ package org.apache.catalina.session;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
-import java.io.InputStream;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Date;
@@ -46,7 +43,6 @@ import java.util.concurrent.atomic.AtomicLong;
import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.Engine;
-import org.apache.catalina.Globals;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Manager;
import org.apache.catalina.Session;
@@ -73,12 +69,6 @@ public abstract class ManagerBase extends LifecycleMBeanBase
// ----------------------------------------------------- Instance Variables
- protected volatile Queue randomInputStreams =
- new ConcurrentLinkedQueue();
- protected String randomFile = "/dev/urandom";
- protected String randomFileCurrent = null;
- protected volatile boolean randomFileCurrentIsValid = true;
-
/**
* The Container with which this Manager is associated.
*/
@@ -137,6 +127,27 @@ public abstract class ManagerBase extends LifecycleMBeanBase
protected String secureRandomClass = null;
/**
+ * The name of the algorithm to use to create instances of
+ * {@link SecureRandom} which are used to generate session IDs. If no
+ * algorithm is specified, SHA1PRNG is used. To use the platform default
+ * (which may be SHA1PRNG), specify the empty string. If an invalid
+ * algorithm and/or provider is specified the {@link SecureRandom} instances
+ * will be created using the defaults. If that fails, the {@link
+ * SecureRandom} instances will be created using platform defaults.
+ */
+ protected String secureRandomAlgorithm = "SHA1PRNG";
+
+ /**
+ * The name of the provider to use to create instances of
+ * {@link SecureRandom} which are used to generate session IDs. If
+ * no algorithm is specified the of SHA1PRNG default is used. If an invalid
+ * algorithm and/or provider is specified the {@link SecureRandom} instances
+ * will be created using the defaults. If that fails, the {@link
+ * SecureRandom} instances will be created using platform defaults.
+ */
+ protected String secureRandomProvider = null;
+
+ /**
* The longest time (in seconds) that an expired session had been alive.
*/
protected volatile int sessionMaxAliveTime;
@@ -214,37 +225,6 @@ public abstract class ManagerBase extends LifecycleMBeanBase
protected PropertyChangeSupport support = new PropertyChangeSupport(this);
- // ------------------------------------------------------------- Security classes
-
-
- private class PrivilegedCreateRandomInputStream
- implements PrivilegedAction {
-
- @Override
- public InputStream run(){
- try {
- File f = new File(randomFileCurrent);
- if (!f.exists()) {
- randomFileCurrentIsValid = false;
- closeRandomInputStreams();
- return null;
- }
- InputStream is = new FileInputStream(f);
- is.read();
- if( log.isDebugEnabled() )
- log.debug( "Opening " + randomFileCurrent );
- randomFileCurrentIsValid = true;
- return is;
- } catch (IOException ex){
- log.warn("Error reading " + randomFileCurrent, ex);
- randomFileCurrentIsValid = false;
- closeRandomInputStreams();
- }
- return null;
- }
- }
-
-
// ------------------------------------------------------------- Properties
/**
@@ -405,95 +385,6 @@ public abstract class ManagerBase extends LifecycleMBeanBase
}
- /**
- * 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 )
- randomFile = s;
- }
-
- protected InputStream createRandomInputStream() {
- if (Globals.IS_SECURITY_ENABLED){
- return AccessController.doPrivileged(
- new PrivilegedCreateRandomInputStream());
- } else {
- try{
- File f = new File(randomFileCurrent);
- if (!f.exists()) {
- randomFileCurrentIsValid = false;
- closeRandomInputStreams();
- return null;
- }
- InputStream is = new FileInputStream(f);
- is.read();
- if( log.isDebugEnabled() )
- log.debug( "Opening " + randomFileCurrent );
- randomFileCurrentIsValid = true;
- return is;
- } catch( IOException ex ) {
- log.warn("Error reading " + randomFileCurrent, ex);
- randomFileCurrentIsValid = false;
- closeRandomInputStreams();
- }
- return null;
- }
- }
-
-
- /**
- * Obtain the value of the randomFile attribute currently configured for
- * this Manager. Note that this will not return the same value as
- * {@link #getRandomFileCurrent()} if the value for the randomFile attribute
- * has been changed since this Manager was started.
- *
- * @return The file currently configured to provide random data for use in
- * generating session IDs
- */
- public String getRandomFile() {
- return randomFile;
- }
-
-
- /**
- * Obtain the value of the randomFile attribute currently being used by
- * this Manager. Note that this will not return the same value as
- * {@link #getRandomFile()} if the value for the randomFile attribute has
- * been changed since this Manager was started.
- *
- * @return The file currently being used to provide random data for use in
- * generating session IDs
- */
- public String getRandomFileCurrent() {
- return randomFileCurrent;
- }
-
-
- protected synchronized void closeRandomInputStreams() {
- InputStream is = randomInputStreams.poll();
-
- while (is != null) {
- try {
- is.close();
- } catch (Exception e) {
- log.warn("Failed to close randomInputStream.");
- }
- is = randomInputStreams.poll();
- }
- }
-
/**
* Create a new random number generator instance we should use for
* generating session identifiers.
@@ -509,17 +400,46 @@ public abstract class ManagerBase extends LifecycleMBeanBase
Class> clazz = Class.forName(secureRandomClass);
result = (SecureRandom) clazz.newInstance();
} catch (Exception e) {
- // Fall back to the default case
log.error(sm.getString("managerBase.random",
secureRandomClass), e);
}
}
+
+ if (result == null) {
+ // No secureRandomClass or creation failed. Use SecureRandom.
+ try {
+ if (secureRandomProvider != null &&
+ secureRandomProvider.length() > 0) {
+ result = SecureRandom.getInstance(secureRandomAlgorithm,
+ secureRandomProvider);
+ } else if (secureRandomAlgorithm != null &&
+ secureRandomAlgorithm.length() > 0) {
+ result = SecureRandom.getInstance(secureRandomAlgorithm);
+ }
+ } catch (NoSuchAlgorithmException e) {
+ log.error(sm.getString("managerBase.randomAlgorithm",
+ secureRandomAlgorithm), e);
+ } catch (NoSuchProviderException e) {
+ log.error(sm.getString("managerBase.randomProvider",
+ secureRandomProvider), e);
+ }
+ }
+
+ if (result == null) {
+ // Invalid provider / algorithm
+ try {
+ result = SecureRandom.getInstance("SHA1PRNG");
+ } catch (NoSuchAlgorithmException e) {
+ log.error(sm.getString("managerBase.randomAlgorithm",
+ secureRandomAlgorithm), e);
+ }
+ }
if (result == null) {
- // No secureRandomClass or creation failed
+ // Nothing works - use platform default
result = new SecureRandom();
}
-
+
if(log.isDebugEnabled()) {
long t2=System.currentTimeMillis();
if( (t2-t1) > 100 )
@@ -531,7 +451,7 @@ public abstract class ManagerBase extends LifecycleMBeanBase
/**
- * Return the random number generator class name.
+ * Return the secure random number generator class name.
*/
public String getSecureRandomClass() {
@@ -541,21 +461,59 @@ public abstract class ManagerBase extends LifecycleMBeanBase
/**
- * Set the random number generator class name.
+ * Set the secure random number generator class name.
*
- * @param randomClass The new random number generator class name
+ * @param randomClass The new secure random number generator class name
*/
- public void setSecureRandomClass(String randomClass) {
+ public void setSecureRandomClass(String secureRandomClass) {
- String oldRandomClass = this.secureRandomClass;
- this.secureRandomClass = randomClass;
- support.firePropertyChange("randomClass", oldRandomClass,
+ String oldSecureRandomClass = this.secureRandomClass;
+ this.secureRandomClass = secureRandomClass;
+ support.firePropertyChange("secureRandomClass", oldSecureRandomClass,
this.secureRandomClass);
}
/**
+ * Return the secure random number generator algorithm name.
+ */
+ public String getSecureRandomAlgorithm() {
+ return secureRandomAlgorithm;
+ }
+
+
+ /**
+ * Set the secure random number generator algorithm name.
+ *
+ * @param secureRandomAlgorithm The new secure random number generator
+ * algorithm name
+ */
+ public void setSecureRandomAlgorithm(String secureRandomAlgorithm) {
+ this.secureRandomAlgorithm = secureRandomAlgorithm;
+ }
+
+
+ /**
+ * Return the secure random number generator provider name.
+ */
+ public String getSecureRandomProvider() {
+ return secureRandomProvider;
+ }
+
+
+ /**
+ * Set the secure random number generator provider name.
+ *
+ * @param secureRandomProvider The new secure random number generator
+ * provider name
+ */
+ public void setSecureRandomProvider(String secureRandomProvider) {
+ this.secureRandomProvider = secureRandomProvider;
+ }
+
+
+ /**
* Number of session creations that failed due to maxActiveSessions
*
* @return The count
@@ -669,12 +627,6 @@ public abstract class ManagerBase extends LifecycleMBeanBase
@Override
protected void startInternal() throws LifecycleException {
- randomFileCurrent = randomFile;
- InputStream is = createRandomInputStream();
- if (is != null) {
- randomInputStreams.add(is);
- }
-
// Ensure caches for timing stats are the right size by filling with
// nulls.
while (sessionCreationTiming.size() < TIMING_STATS_CACHE_SIZE) {
@@ -694,7 +646,7 @@ public abstract class ManagerBase extends LifecycleMBeanBase
@Override
protected void stopInternal() throws LifecycleException {
- closeRandomInputStreams();
+ this.randoms.clear();
}
@@ -899,31 +851,7 @@ public abstract class ManagerBase extends LifecycleMBeanBase
protected void getRandomBytes(byte bytes[]) {
- if (randomFileCurrentIsValid) {
- InputStream is = null;
- try {
- // If one of the InputStreams fails, is will be null and the
- // resulting NPE will trigger a fall-back to getRandom()
- is = randomInputStreams.poll();
- if (is == null) {
- is = createRandomInputStream();
- }
- int len = is.read(bytes);
- if (len == bytes.length) {
- randomInputStreams.add(is);
- return;
- }
- if(log.isDebugEnabled())
- log.debug("Got " + len + " " + bytes.length );
- } catch (Exception ex) {
- // Ignore
- }
- randomFileCurrentIsValid = false;
- if (is != null) {
- randomInputStreams.add(is);
- }
- closeRandomInputStreams();
- }
+
SecureRandom random = randoms.poll();
if (random == null) {
random = createSecureRandom();
diff --git a/java/org/apache/catalina/session/PersistentManagerBase.java b/java/org/apache/catalina/session/PersistentManagerBase.java
index 2622071f7..65bf88e7e 100644
--- a/java/org/apache/catalina/session/PersistentManagerBase.java
+++ b/java/org/apache/catalina/session/PersistentManagerBase.java
@@ -865,7 +865,6 @@ public abstract class PersistentManagerBase extends ManagerBase {
((Lifecycle)getStore()).stop();
// Require a new random number generator if we are restarted
- this.randoms.clear();
super.stopInternal();
}
diff --git a/java/org/apache/catalina/session/StandardManager.java b/java/org/apache/catalina/session/StandardManager.java
index 263958f34..158ba1977 100644
--- a/java/org/apache/catalina/session/StandardManager.java
+++ b/java/org/apache/catalina/session/StandardManager.java
@@ -513,7 +513,6 @@ public class StandardManager extends ManagerBase {
}
// Require a new random number generator if we are restarted
- this.randoms.clear();
super.stopInternal();
}
diff --git a/java/org/apache/catalina/session/mbeans-descriptors.xml b/java/org/apache/catalina/session/mbeans-descriptors.xml
index 844b1e174..5c055bea9 100644
--- a/java/org/apache/catalina/session/mbeans-descriptors.xml
+++ b/java/org/apache/catalina/session/mbeans-descriptors.xml
@@ -83,8 +83,16 @@
description="Time spent doing housekeeping and expiration"
type="long" />
+
+
+
+
Further performance improvements to session ID generation. Remove legacy
- configuration options that are no longer required. (markt)
+ configuration options that are no longer required. Provide additional
+ options to control the SecureRandom instances used to
+ generate session IDs. (markt)
50351: Fix the regression that broke BeanFactory resources
diff --git a/webapps/docs/config/manager.xml b/webapps/docs/config/manager.xml
index 292a5a211..c6775fa51 100644
--- a/webapps/docs/config/manager.xml
+++ b/webapps/docs/config/manager.xml
@@ -133,13 +133,33 @@
-
+
Name of the Java class that extends
java.security.SecureRandom to use to generate session IDs.
If not specified, the default value is
java.security.SecureRandom.
+
+ Name of the provider to use to create the
+ java.security.SecureRandom instances that generate session
+ IDs. If an invalid algorithm and/or provider is specified, the Manager
+ will use the platform default provider and the default algorithm. If not
+ specified, the platform default provider will be used.
+
+
+
+ Name of the algorithm to use to create the
+ java.security.SecureRandom instances that generate session
+ IDs. If an invalid algorithm and/or provider is specified, the Manager
+ will use the platform default provider and the default algorithm. If not
+ specified, the default algorithm of SHA1PRNG will be used. If the
+ default algorithm is not supported, the platform default will be used.
+ To specify that the platform default should be used, do not set the
+ secureRandomProvider attribute and set this attribute to the empty
+ string.
+
+
The length of session ids created by this Manager, excluding any
JVM route information used for load balancing.