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-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org