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