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.