You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2014/09/25 21:33:31 UTC

svn commit: r1627611 - in /tomcat/trunk/java/org/apache/catalina: ./ realm/

Author: markt
Date: Thu Sep 25 19:33:29 2014
New Revision: 1627611

URL: http://svn.apache.org/r1627611
Log:
Restore mutate() to a single parameter method
CHBase only of digest CH's so rename it
Add support for nested CH

Added:
    tomcat/trunk/java/org/apache/catalina/realm/DigestCredentialHandlerBase.java   (contents, props changed)
      - copied, changed from r1627610, tomcat/trunk/java/org/apache/catalina/realm/CredentialHandlerBase.java
    tomcat/trunk/java/org/apache/catalina/realm/NestedCredentialHandler.java   (with props)
Removed:
    tomcat/trunk/java/org/apache/catalina/realm/CredentialHandlerBase.java
Modified:
    tomcat/trunk/java/org/apache/catalina/CredentialHandler.java
    tomcat/trunk/java/org/apache/catalina/realm/MessageDigestCredentialHandler.java
    tomcat/trunk/java/org/apache/catalina/realm/PBECredentialHandler.java
    tomcat/trunk/java/org/apache/catalina/realm/RealmBase.java

Modified: tomcat/trunk/java/org/apache/catalina/CredentialHandler.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/CredentialHandler.java?rev=1627611&r1=1627610&r2=1627611&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/CredentialHandler.java (original)
+++ tomcat/trunk/java/org/apache/catalina/CredentialHandler.java Thu Sep 25 19:33:29 2014
@@ -38,13 +38,9 @@ public interface CredentialHandler {
      * credentials.
      *
      * @param inputCredentials  User provided credentials
-     * @param salt              Salt, if any
-     * @param iterations        Number of iterations of the algorithm associated
-     *                          with this CredentialHandler applied to the
-     *                          inputCredentials to generate the equivalent
-     *                          stored credentials
+     *
      * @return  The equivalent stored credentials for the given input
      *          credentials
      */
-    String mutate(String inputCredentials, byte[] salt, int iterations);
+    String mutate(String inputCredentials);
 }

Copied: tomcat/trunk/java/org/apache/catalina/realm/DigestCredentialHandlerBase.java (from r1627610, tomcat/trunk/java/org/apache/catalina/realm/CredentialHandlerBase.java)
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/realm/DigestCredentialHandlerBase.java?p2=tomcat/trunk/java/org/apache/catalina/realm/DigestCredentialHandlerBase.java&p1=tomcat/trunk/java/org/apache/catalina/realm/CredentialHandlerBase.java&r1=1627610&r2=1627611&rev=1627611&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/realm/CredentialHandlerBase.java (original)
+++ tomcat/trunk/java/org/apache/catalina/realm/DigestCredentialHandlerBase.java Thu Sep 25 19:33:29 2014
@@ -28,17 +28,22 @@ import org.apache.tomcat.util.res.String
 /**
  * Base implementation for the Tomcat provided {@link CredentialHandler}s.
  */
-public abstract class CredentialHandlerBase implements CredentialHandler {
+public abstract class DigestCredentialHandlerBase implements CredentialHandler {
 
     protected static final StringManager sm = StringManager.getManager(Constants.Package);
 
+    public static final int DEFAULT_SALT_LENGTH = 32;
+
     private int iterations = getDefaultIterations();
-    private Random random = null;
+    private int saltLength = getDefaultSaltLength();
+    private final Object randomLock = new Object();
+    private volatile Random random = null;
+    private boolean logInvalidStoredCredentials = false;
 
 
     /**
      * Return the number of iterations of the associated algorithm that will be
-     * used to convert the plain text credential into the stored credential.
+     * used when creating a new stored credential for a given input credential.
      */
     public int getIterations() {
         return iterations;
@@ -47,7 +52,7 @@ public abstract class CredentialHandlerB
 
     /**
      * Set the number of iterations of the associated algorithm that will be
-     * used to convert the plain text credential into the stored credential.
+     * used when creating a new stored credential for a given input credential.
      */
     public void setIterations(int iterations) {
         this.iterations = iterations;
@@ -55,24 +60,61 @@ public abstract class CredentialHandlerB
 
 
     /**
-     * Generate a stored credential from the given plain text credential.
-     *
-     * @param saltLength        Length of random salt to be generated and used
-     *                          as part of the transformation
-     * @param userCredential    The plain text credential
-     *
-     * @return  The credential to be stored
+     * Return the salt length that will be used when creating a new stored
+     * credential for a given input credential.
+     */
+    public int getSaltLength() {
+        return saltLength;
+    }
+
+
+    /**
+     * Set the salt length that will be used when creating a new stored
+     * credential for a given input credential.
+     */
+    public void setSaltLength(int saltLength) {
+        this.saltLength = saltLength;
+    }
+
+
+    /**
+     * When checking input credentials against stored credentials will a warning
+     * message be logged if invalid stored credentials are discovered?
+     */
+    public boolean getLogInvalidStoredCredentials() {
+        return logInvalidStoredCredentials;
+    }
+
+
+    /**
+     * Set whether a warning message will be logged if invalid stored
+     * credentials are discovered while checking input credentials against
+     * stored credentials?
      */
-    public String generate(int saltLength, String userCredential) {
+    public void setLogInvalidStoredCredentials(boolean logInvalidStoredCredentials) {
+        this.logInvalidStoredCredentials = logInvalidStoredCredentials;
+    }
+
+
+    @Override
+    public String mutate(String userCredential) {
         byte[] salt = null;
         int iterations = getIterations();
+        int saltLength = getSaltLength();
         if (saltLength == 0) {
             salt = new byte[0];
         } else if (saltLength > 0) {
+            // Double checked locking. OK since random is volatile.
             if (random == null) {
-                random = new SecureRandom();
+                synchronized (randomLock) {
+                    if (random == null) {
+                        random = new SecureRandom();
+                    }
+                }
             }
             salt = new byte[saltLength];
+            // Concurrent use of this random is unlikely to be a performance
+            // issue as it is only used during stored password generation.
             random.nextBytes(salt);
         }
 
@@ -107,10 +149,13 @@ public abstract class CredentialHandlerB
 
         if (sep1 < 0 || sep2 < 0) {
             // Stored credentials are invalid
-            // Logging credentials could be a security concern but they are
-            // invalid and that is a bigger problem
-            getLog().warn(sm.getString("credentialHandler.invalidStoredCredential",
-                    storedCredentials));
+            // This may be expected if nested credential handlers are being used
+            if (logInvalidStoredCredentials) {
+                // Logging credentials could be a security concern but they are
+                // invalid and that is probably a bigger problem
+                getLog().warn(sm.getString("credentialHandler.invalidStoredCredential",
+                        storedCredentials));
+            }
             return false;
         }
 
@@ -128,6 +173,30 @@ public abstract class CredentialHandlerB
 
 
     /**
+     * Get the default salt length used by the {@link CredentialHandler}.
+     */
+    protected int getDefaultSaltLength() {
+        return DEFAULT_SALT_LENGTH;
+    }
+
+
+    /**
+     * Generates the equivalent stored credentials for the given input
+     * credentials, salt and iterations.
+     *
+     * @param inputCredentials  User provided credentials
+     * @param salt              Salt, if any
+     * @param iterations        Number of iterations of the algorithm associated
+     *                          with this CredentialHandler applied to the
+     *                          inputCredentials to generate the equivalent
+     *                          stored credentials
+     *
+     * @return  The equivalent stored credentials for the given input
+     *          credentials
+     */
+    protected abstract String mutate(String inputCredentials, byte[] salt, int iterations);
+
+    /**
      * Set the algorithm used to convert input credentials to stored
      * credentials.
      */

Propchange: tomcat/trunk/java/org/apache/catalina/realm/DigestCredentialHandlerBase.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/java/org/apache/catalina/realm/MessageDigestCredentialHandler.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/realm/MessageDigestCredentialHandler.java?rev=1627611&r1=1627610&r2=1627611&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/realm/MessageDigestCredentialHandler.java (original)
+++ tomcat/trunk/java/org/apache/catalina/realm/MessageDigestCredentialHandler.java Thu Sep 25 19:33:29 2014
@@ -52,7 +52,7 @@ import org.apache.tomcat.util.security.C
  * <p>
  * If the stored password form does not include salt then no salt is used.
  */
-public class MessageDigestCredentialHandler extends CredentialHandlerBase {
+public class MessageDigestCredentialHandler extends DigestCredentialHandlerBase {
 
     private static final Log log = LogFactory.getLog(MessageDigestCredentialHandler.class);
 
@@ -157,7 +157,7 @@ public class MessageDigestCredentialHand
 
 
     @Override
-    public String mutate(String inputCredentials, byte[] salt, int iterations) {
+    protected String mutate(String inputCredentials, byte[] salt, int iterations) {
         if (algorithm == null) {
             return inputCredentials;
         } else {

Added: tomcat/trunk/java/org/apache/catalina/realm/NestedCredentialHandler.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/realm/NestedCredentialHandler.java?rev=1627611&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/realm/NestedCredentialHandler.java (added)
+++ tomcat/trunk/java/org/apache/catalina/realm/NestedCredentialHandler.java Thu Sep 25 19:33:29 2014
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.catalina.realm;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.catalina.CredentialHandler;
+
+public class NestedCredentialHandler implements CredentialHandler {
+
+    private final List<CredentialHandler> credentialHandlers = new ArrayList<>();
+
+
+    @Override
+    public boolean matches(String inputCredentials, String storedCredentials) {
+        for (CredentialHandler handler : credentialHandlers) {
+            if (handler.matches(inputCredentials, storedCredentials)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    /**
+     * The input credentials will be passed to the first nested
+     * {@link CredentialHandler}. If no nested {@link CredentialHandler} are
+     * configured then <code>null</code> will be returned.
+     *
+     * {@inheritDoc}
+     */
+    @Override
+    public String mutate(String inputCredentials) {
+        if (credentialHandlers.isEmpty()) {
+            return null;
+        }
+
+        return credentialHandlers.get(0).mutate(inputCredentials);
+    }
+}

Propchange: tomcat/trunk/java/org/apache/catalina/realm/NestedCredentialHandler.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: tomcat/trunk/java/org/apache/catalina/realm/PBECredentialHandler.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/realm/PBECredentialHandler.java?rev=1627611&r1=1627610&r2=1627611&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/realm/PBECredentialHandler.java (original)
+++ tomcat/trunk/java/org/apache/catalina/realm/PBECredentialHandler.java Thu Sep 25 19:33:29 2014
@@ -27,7 +27,7 @@ import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.buf.HexUtils;
 
-public class PBECredentialHandler extends CredentialHandlerBase {
+public class PBECredentialHandler extends DigestCredentialHandlerBase {
 
     private static final Log log = LogFactory.getLog(PBECredentialHandler.class);
 
@@ -35,6 +35,7 @@ public class PBECredentialHandler extend
     public static final int DEFAULT_KEY_LENGTH = 160;
     public static final int DEFAULT_ITERATIONS = 20000;
 
+
     private SecretKeyFactory secretKeyFactory;
     private int keyLength = DEFAULT_KEY_LENGTH;
 

Modified: tomcat/trunk/java/org/apache/catalina/realm/RealmBase.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/realm/RealmBase.java?rev=1627611&r1=1627610&r2=1627611&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/realm/RealmBase.java (original)
+++ tomcat/trunk/java/org/apache/catalina/realm/RealmBase.java Thu Sep 25 19:33:29 2014
@@ -51,6 +51,7 @@ import org.apache.catalina.util.Lifecycl
 import org.apache.catalina.util.SessionConfig;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.IntrospectionUtils;
 import org.apache.tomcat.util.buf.B2CConverter;
 import org.apache.tomcat.util.buf.HexUtils;
 import org.apache.tomcat.util.codec.binary.Base64;
@@ -75,7 +76,7 @@ public abstract class RealmBase extends 
 
     private static final Log log = LogFactory.getLog(RealmBase.class);
 
-    private static final List<Class<? extends CredentialHandlerBase>> credentialHandlerClasses =
+    private static final List<Class<? extends DigestCredentialHandlerBase>> credentialHandlerClasses =
             new ArrayList<>();
 
     static {
@@ -1437,11 +1438,11 @@ public abstract class RealmBase extends 
      *                 stored credential. If not specified, the default for the
      *                 CredentialHandler will be used.</li>
      * <li><b>-s</b> - The length (in bytes) of salt to generate and store as
-     *                 part of the credential. If not specified, a default of 32
-     *                 will be used.</li>
+     *                 part of the credential. If not specified, the default for
+     *                 the CredentialHandler will be used.</li>
      * <li><b>-k</b> - The length (in bits) of the key(s), if any, created while
-     *                 generating the credential. If not specified, a default of
-     *                 160 will be used.</li>
+     *                 generating the credential. If not specified, the default
+     *                 for the CredentialHandler will be used.</li>
      * <li><b>-h</b> - The fully qualified class name of the CredentialHandler
      *                 to use. If not specified, the built-in handlers will be
      *                 tested in turn and the first one to accept the specified
@@ -1459,9 +1460,9 @@ public abstract class RealmBase extends 
 
         String algorithm = "SHA-512";
         String encoding = "UTF-8";
-        int saltLength = 32;
-        int iterations = 0;
-        int keyLength = 160;
+        int saltLength = -1;
+        int iterations = -1;
+        int keyLength = -1;
         String handlerClassName = null;
 
         int argIndex = 0;
@@ -1495,22 +1496,23 @@ public abstract class RealmBase extends 
             }
             default: {
                 System.out.println("Usage: RealmBase [-a <algorithm>] [-e <encoding>] " +
-                        "[-s <salt-length>] [-k <key-length>] <credentials>");
+                        "[-i <iterations>] [-s <salt-length>] [-k <key-length>] " +
+                        "[-h <handler-class-name>] <credentials>");
                 return;
             }
             }
             argIndex += 2;
         }
 
-        CredentialHandlerBase handler = null;
+        CredentialHandler handler = null;
 
         if (handlerClassName == null) {
-            for (Class<? extends CredentialHandlerBase> clazz : credentialHandlerClasses) {
+            for (Class<? extends DigestCredentialHandlerBase> clazz : credentialHandlerClasses) {
                 try {
                     handler = clazz.newInstance();
-                    handler.setAlgorithm(algorithm);
-                } catch (NoSuchAlgorithmException e) {
-                    // Ignore - Algorithm is for a different CredentialHandler
+                    if (IntrospectionUtils.setProperty(handler, "algorithm", algorithm)) {
+                        break;
+                    }
                 } catch (InstantiationException | IllegalAccessException e) {
                     // This isn't good.
                     throw new RuntimeException(e);
@@ -1519,10 +1521,10 @@ public abstract class RealmBase extends 
         } else {
             try {
                 Class<?> clazz = Class.forName(handlerClassName);
-                handler = (CredentialHandlerBase) clazz.newInstance();
-                handler.setAlgorithm(algorithm);
+                handler = (DigestCredentialHandlerBase) clazz.newInstance();
+                IntrospectionUtils.setProperty(handler, "algorithm", algorithm);
             } catch (InstantiationException | IllegalAccessException
-                    | ClassNotFoundException | NoSuchAlgorithmException e) {
+                    | ClassNotFoundException e) {
                 throw new RuntimeException(e);
             }
         }
@@ -1531,20 +1533,21 @@ public abstract class RealmBase extends 
             throw new RuntimeException(new NoSuchAlgorithmException(algorithm));
         }
 
+        IntrospectionUtils.setProperty(handler, "encoding", encoding);
         if (iterations > 0) {
-            handler.setIterations(iterations);
+            IntrospectionUtils.setProperty(handler, "iterations", Integer.toString(iterations));
         }
-
-        if (handler instanceof MessageDigestCredentialHandler) {
-            ((MessageDigestCredentialHandler) handler).setEncoding(encoding);
-        } else if (handler instanceof PBECredentialHandler) {
-            ((PBECredentialHandler) handler).setKeyLength(keyLength);
+        if (saltLength > -1) {
+            IntrospectionUtils.setProperty(handler, "saltLength", Integer.toString(saltLength));
+        }
+        if (keyLength > 0) {
+            IntrospectionUtils.setProperty(handler, "keyLength", Integer.toString(keyLength));
         }
 
         for (; argIndex < args.length; argIndex++) {
             String credential = args[argIndex];
-            System.out.println(credential);
-            handler.generate(saltLength, credential);
+            System.out.print(credential + ":");
+            System.out.println(handler.mutate(credential));
         }
     }
 



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org