Author: markt
Date: Thu Sep 25 19:32:39 2014
New Revision: 1627601
URL: http://svn.apache.org/r1627601
Log:
Hook up credential generation
Modified:
tomcat/trunk/java/org/apache/catalina/realm/CredentialHandlerBase.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
tomcat/trunk/test/org/apache/catalina/realm/TestRealmBase.java
Modified: tomcat/trunk/java/org/apache/catalina/realm/CredentialHandlerBase.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/realm/CredentialHandlerBase.java?rev=1627601&r1=1627600&r2=1627601&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/realm/CredentialHandlerBase.java
(original)
+++ tomcat/trunk/java/org/apache/catalina/realm/CredentialHandlerBase.java Thu
Sep 25 19:32:39 2014
@@ -16,6 +16,10 @@
*/
package org.apache.catalina.realm;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Random;
+
import org.apache.catalina.CredentialHandler;
import org.apache.tomcat.util.buf.HexUtils;
import org.apache.tomcat.util.res.StringManager;
@@ -24,6 +28,37 @@ public abstract class CredentialHandlerB
protected static final StringManager sm =
StringManager.getManager(Constants.Package);
+ private int iterations = getDefaultIterations();
+ private Random random = null;
+
+
+ public int getIterations() {
+ return iterations;
+ }
+
+
+ public void setIterations(int iterations) {
+ this.iterations = iterations;
+ }
+
+
+ public String generate(int saltLength, String userCredential) {
+ byte[] salt = null;
+ int iterations = getIterations();
+ if (saltLength > 0) {
+ if (random == null) {
+ random = new SecureRandom();
+ }
+ salt = new byte[saltLength];
+ random.nextBytes(salt);
+ }
+
+ String serverCredential = mutate(userCredential, salt, iterations);
+
+ return HexUtils.toHexString(salt) + "$" + iterations + "$" +
serverCredential;
+ }
+
+
protected boolean matchesSaltIterationsEncoded(String inputCredentials,
String storedCredentials) {
int sep1 = storedCredentials.indexOf('$');
@@ -40,4 +75,9 @@ public abstract class CredentialHandlerB
return storedHexEncoded.equalsIgnoreCase(inputHexEncoded);
}
+
+
+ protected abstract void setAlgorithm(String algorithm) throws
NoSuchAlgorithmException;
+
+ protected abstract int getDefaultIterations();
}
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=1627601&r1=1627600&r2=1627601&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:32:39 2014
@@ -56,8 +56,10 @@ public class MessageDigestCredentialHand
private static final Log log =
LogFactory.getLog(MessageDigestCredentialHandler.class);
+ public static final int DEFAULT_ITERATIONS = 1;
+
private Charset encoding = StandardCharsets.UTF_8;
- private String digest = null;
+ private String algorithm = null;
public String getEncoding() {
@@ -79,18 +81,15 @@ public class MessageDigestCredentialHand
}
- public String getDigest() {
- return digest;
+ public String getAlgorithm() {
+ return algorithm;
}
- public void setDigest(String digest) {
- try {
- MessageDigest.getInstance(digest);
- } catch (NoSuchAlgorithmException e) {
- throw new IllegalArgumentException(e);
- }
- this.digest = digest;
+ @Override
+ public void setAlgorithm(String algorithm) throws NoSuchAlgorithmException
{
+ MessageDigest.getInstance(algorithm);
+ this.algorithm = algorithm;
}
@@ -101,7 +100,7 @@ public class MessageDigestCredentialHand
return false;
}
- if (getDigest() == null) {
+ if (getAlgorithm() == null) {
// No digests, compare directly
return storedCredentials.equals(inputCredentials);
} else {
@@ -114,7 +113,7 @@ public class MessageDigestCredentialHand
// the digest type
String serverDigest = storedCredentials.substring(5);
String userDigest =
Base64.encodeBase64String(ConcurrentMessageDigest.digest(
- getDigest(),
inputCredentials.getBytes(StandardCharsets.ISO_8859_1)));
+ getAlgorithm(),
inputCredentials.getBytes(StandardCharsets.ISO_8859_1)));
return userDigest.equals(serverDigest);
} else if (storedCredentials.startsWith("{SSHA}")) {
@@ -138,7 +137,7 @@ public class MessageDigestCredentialHand
// Generate the digested form of the user provided password
// using the salt
- byte[] userDigestBytes =
ConcurrentMessageDigest.digest(getDigest(),
+ byte[] userDigestBytes =
ConcurrentMessageDigest.digest(getAlgorithm(),
inputCredentials.getBytes(StandardCharsets.ISO_8859_1),
serverSaltBytes);
@@ -158,18 +157,24 @@ public class MessageDigestCredentialHand
@Override
public String mutate(String inputCredentials, byte[] salt, int iterations)
{
- if (digest == null) {
+ if (algorithm == null) {
return inputCredentials;
} else {
byte[] userDigest;
if (salt == null) {
- userDigest = ConcurrentMessageDigest.digest(digest, iterations,
+ userDigest = ConcurrentMessageDigest.digest(algorithm,
iterations,
inputCredentials.getBytes(encoding));
} else {
- userDigest = ConcurrentMessageDigest.digest(digest, iterations,
+ userDigest = ConcurrentMessageDigest.digest(algorithm,
iterations,
salt, inputCredentials.getBytes(encoding));
}
return HexUtils.toHexString(userDigest);
}
}
+
+
+ @Override
+ protected int getDefaultIterations() {
+ return DEFAULT_ITERATIONS;
+ }
}
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=1627601&r1=1627600&r2=1627601&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:32:39 2014
@@ -32,10 +32,11 @@ public class PBECredentialHandler extend
private static final Log log =
LogFactory.getLog(PBECredentialHandler.class);
public static final String DEFAULT_ALGORITHM = "PBKDF2WithHmacSHA1";
- public static final int DEFAULT_KEYLENGTH = 160;
+ public static final int DEFAULT_KEY_LENGTH = 160;
+ public static final int DEFAULT_ITERATIONS = 20000;
private SecretKeyFactory secretKeyFactory;
- private int keyLength = 160;
+ private int keyLength = DEFAULT_KEY_LENGTH;
public PBECredentialHandler() throws NoSuchAlgorithmException {
@@ -48,6 +49,7 @@ public class PBECredentialHandler extend
}
+ @Override
public void setAlgorithm(String algorithm) throws NoSuchAlgorithmException
{
SecretKeyFactory secretKeyFactory =
SecretKeyFactory.getInstance(algorithm);
this.secretKeyFactory = secretKeyFactory;
@@ -81,4 +83,10 @@ public class PBECredentialHandler extend
return null;
}
}
+
+
+ @Override
+ protected int getDefaultIterations() {
+ return DEFAULT_ITERATIONS;
+ }
}
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=1627601&r1=1627600&r2=1627601&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:32:39 2014
@@ -29,6 +29,7 @@ import java.security.Principal;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Locale;
import javax.servlet.http.HttpServletResponse;
@@ -74,6 +75,14 @@ public abstract class RealmBase extends
private static final Log log = LogFactory.getLog(RealmBase.class);
+ private static final List<Class<? extends CredentialHandlerBase>>
credentialHandlerClasses =
+ new ArrayList<>();
+
+ static {
+ credentialHandlerClasses.add(MessageDigestCredentialHandler.class);
+ credentialHandlerClasses.add(PBECredentialHandler.class);
+ }
+
// ----------------------------------------------------- Instance Variables
@@ -240,7 +249,7 @@ public abstract class RealmBase extends
public String getDigest() {
CredentialHandler ch = credentialHandler;
if (ch instanceof MessageDigestCredentialHandler) {
- return ((MessageDigestCredentialHandler) ch).getDigest();
+ return ((MessageDigestCredentialHandler) ch).getAlgorithm();
}
return null;
}
@@ -262,7 +271,11 @@ public abstract class RealmBase extends
credentialHandler = ch;
}
if (ch instanceof MessageDigestCredentialHandler) {
- ((MessageDigestCredentialHandler) ch).setDigest(digest);
+ try {
+ ((MessageDigestCredentialHandler) ch).setAlgorithm(digest);
+ } catch (NoSuchAlgorithmException e) {
+ throw new IllegalArgumentException(e);
+ }
} else {
log.warn(sm.getString("realmBase.credentialHandler.customCredentialHandler",
"digest", digest));
@@ -1411,30 +1424,108 @@ public abstract class RealmBase extends
/**
- * Digest password using the algorithm specified and
- * convert the result to a corresponding hex string.
- * If exception, the plain credentials string is returned
+ * Generate a stored credential string for the given password and
associated
+ * parameters. The following parameters are supported:
+ * <ul>
+ * <li><b>-a</b> - The algorithm to use to generate the stored
+ * credential. If not specified a default of SHA-512 will
be
+ * used.</li>
+ * <li><b>-e</b> - The encoding to use for any byte to/from character
+ * conversion that may be necessary. If not specified, a
+ * default of UTF-8 will be used.</li>
+ * <li><b>-i</b> - The number of iterations to use when generating the
+ * 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>
+ * <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>
+ * </ul>
+ * This generation process currently supports the following
+ * CredentialHandlers, the correct one being selected based on the
algorithm
+ * specified:
+ * <ul>
+ * <li>MessageDigestCredentialHandler</li>
+ * <li>PBECredentialHandler</li>
+ * </li>
*/
public static void main(String args[]) {
- String encoding = null;
- int firstCredentialArg = 2;
+ String algorithm = "SHA-512";
+ String encoding = "UTF-8";
+ int saltLength = 32;
+ int iterations = 0;
+ int keyLength = 160;
- if (args.length > 4 && args[2].equalsIgnoreCase("-e")) {
- encoding = args[3];
- firstCredentialArg = 4;
+ int argIndex = 0;
+
+ while (args.length > argIndex + 2 && args[argIndex].length() == 2 &&
+ args[argIndex].charAt(0) == '-' ) {
+ switch (args[argIndex].charAt(1)) {
+ case 'a': {
+ algorithm = args[argIndex + 1];
+ break;
+ }
+ case 'e': {
+ encoding = args[argIndex + 1];
+ break;
+ }
+ case 'i': {
+ iterations = Integer.parseInt(args[argIndex + 1]);
+ break;
+ }
+ case 's': {
+ saltLength = Integer.parseInt(args[argIndex + 1]);
+ break;
+ }
+ case 'k': {
+ keyLength = Integer.parseInt(args[argIndex + 1]);
+ break;
+ }
+ default: {
+ System.out.println("Usage: RealmBase [-a <algorithm>] [-e
<encoding>] " +
+ "[-s <salt-length>] [-k <key-length>] <credentials>");
+ return;
+ }
+ }
+ argIndex += 2;
}
- if(args.length > firstCredentialArg && args[0].equalsIgnoreCase("-a"))
{
- for(int i=firstCredentialArg; i < args.length ; i++){
- System.out.print(args[i]+":");
- System.out.println(Digest(args[i], args[1], encoding));
+ CredentialHandlerBase handler = null;
+
+ for (Class<? extends CredentialHandlerBase> clazz :
credentialHandlerClasses) {
+ try {
+ handler = clazz.newInstance();
+ handler.setAlgorithm(algorithm);
+ } catch (NoSuchAlgorithmException e) {
+ // Ignore - Algorithm is for a different CredentialHandler
+ } catch (InstantiationException | IllegalAccessException e) {
+ // This isn't good.
+ throw new RuntimeException(e);
}
- } else {
- System.out.println
- ("Usage: RealmBase -a <algorithm> [-e <encoding>]
<credentials>");
}
+ if (handler == null) {
+ throw new RuntimeException(new
NoSuchAlgorithmException(algorithm));
+ }
+
+ if (iterations > 0) {
+ handler.setIterations(iterations);
+ }
+
+ if (handler instanceof MessageDigestCredentialHandler) {
+ ((MessageDigestCredentialHandler) handler).setEncoding(encoding);
+ } else if (handler instanceof PBECredentialHandler) {
+ ((PBECredentialHandler) handler).setKeyLength(keyLength);
+ }
+
+ for (; argIndex < args.length; argIndex++) {
+ String credential = args[argIndex];
+ System.out.println(credential);
+ handler.generate(saltLength, credential);
+ }
}
Modified: tomcat/trunk/test/org/apache/catalina/realm/TestRealmBase.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/realm/TestRealmBase.java?rev=1627601&r1=1627600&r2=1627601&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/catalina/realm/TestRealmBase.java (original)
+++ tomcat/trunk/test/org/apache/catalina/realm/TestRealmBase.java Thu Sep 25
19:32:39 2014
@@ -90,7 +90,7 @@ public class TestRealmBase {
TesterMapRealm realm = new TesterMapRealm();
realm.setContainer(context);
MessageDigestCredentialHandler ch = new
MessageDigestCredentialHandler();
- ch.setDigest(digest);
+ ch.setAlgorithm(digest);
realm.setCredentialHandler(ch);
realm.start();
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]