View | Details | Raw Unified | Return to bug 60446
Collapse All | Expand All

(-)a/java/org/apache/catalina/realm/DigestCredentialHandlerBase.java (-2 / +22 lines)
Lines 178-189 public abstract class DigestCredentialHandlerBase implements CredentialHandler { Link Here
178
            return false;
178
            return false;
179
        }
179
        }
180
180
181
        String inputHexEncoded = mutate(inputCredentials, salt, iterations);
181
        String inputHexEncoded = mutate(inputCredentials, salt, iterations,
182
                HexUtils.fromHexString(storedHexEncoded).length * Byte.SIZE);
182
183
183
        return storedHexEncoded.equalsIgnoreCase(inputHexEncoded);
184
        return storedHexEncoded.equalsIgnoreCase(inputHexEncoded);
184
    }
185
    }
185
186
186
187
    private void logInvalidStoredCredentials(String storedCredentials) {
187
    private void logInvalidStoredCredentials(String storedCredentials) {
188
        if (logInvalidStoredCredentials) {
188
        if (logInvalidStoredCredentials) {
189
            // Logging credentials could be a security concern but they are
189
            // Logging credentials could be a security concern but they are
Lines 217-222 public abstract class DigestCredentialHandlerBase implements CredentialHandler { Link Here
217
     *          credentials
217
     *          credentials
218
     */
218
     */
219
    protected abstract String mutate(String inputCredentials, byte[] salt, int iterations);
219
    protected abstract String mutate(String inputCredentials, byte[] salt, int iterations);
220
    
221
    /**
222
     * Generates the equivalent stored credentials for the given input
223
     * credentials, salt, iterations and keylength.
224
     *
225
     * @param inputCredentials  User provided credentials
226
     * @param salt              Salt, if any
227
     * @param iterations        Number of iterations of the algorithm associated
228
     *                          with this CredentialHandler applied to the
229
     *                          inputCredentials to generate the equivalent
230
     *                          stored credentials
231
     * @param keyLength         Length of the produced digest in bits for implementations
232
     *                          where it's applicable
233
     *
234
     * @return  The equivalent stored credentials for the given input
235
     *          credentials
236
     */
237
    protected String mutate(String inputCredentials, byte[] salt, int iterations, int keyLength) {
238
        return mutate(inputCredentials, salt, iterations);
239
    }
220
240
221
    /**
241
    /**
222
     * Set the algorithm used to convert input credentials to stored
242
     * Set the algorithm used to convert input credentials to stored
(-)a/java/org/apache/catalina/realm/SecretKeyCredentialHandler.java (-5 / +9 lines)
Lines 72-88 public class SecretKeyCredentialHandler extends DigestCredentialHandlerBase { Link Here
72
    public boolean matches(String inputCredentials, String storedCredentials) {
72
    public boolean matches(String inputCredentials, String storedCredentials) {
73
        return matchesSaltIterationsEncoded(inputCredentials, storedCredentials);
73
        return matchesSaltIterationsEncoded(inputCredentials, storedCredentials);
74
    }
74
    }
75
75
    
76
77
    @Override
76
    @Override
78
    protected String mutate(String inputCredentials, byte[] salt, int iterations) {
77
    protected String mutate(String inputCredentials, byte[] salt, int iterations) {
79
        KeySpec spec = new PBEKeySpec(inputCredentials.toCharArray(), salt, iterations, getKeyLength());
78
        return mutate(inputCredentials, salt, iterations, getKeyLength());
79
    }
80
81
    @Override
82
    protected String mutate(String inputCredentials, byte[] salt, int iterations, int keyLength) {
83
        KeySpec spec = new PBEKeySpec(inputCredentials.toCharArray(), salt, iterations, keyLength);
80
84
81
        try {
85
        try {
82
            return HexUtils.toHexString(secretKeyFactory.generateSecret(spec).getEncoded());
86
            return HexUtils.toHexString(secretKeyFactory.generateSecret(spec).getEncoded());
83
        } catch (InvalidKeySpecException e) {
87
        } catch (InvalidKeySpecException e) {
84
            log.warn("pbeCredentialHandler.invalidKeySpec", e);
88
            log.warn(e.getLocalizedMessage(), e);
85
            return null;
89
            throw new IllegalArgumentException(e);
86
        }
90
        }
87
    }
91
    }
88
92
(-)a/test/org/apache/catalina/realm/TestMessageDigestCredentialHandler.java (-1 / +3 lines)
Lines 49-58 public class TestMessageDigestCredentialHandler { Link Here
49
49
50
    private void doTest(String digest, int saltLength, int iterations) throws NoSuchAlgorithmException {
50
    private void doTest(String digest, int saltLength, int iterations) throws NoSuchAlgorithmException {
51
        MessageDigestCredentialHandler mdch = new MessageDigestCredentialHandler();
51
        MessageDigestCredentialHandler mdch = new MessageDigestCredentialHandler();
52
        MessageDigestCredentialHandler verifier = new MessageDigestCredentialHandler();
52
        mdch.setAlgorithm(digest);
53
        mdch.setAlgorithm(digest);
53
        mdch.setIterations(iterations);
54
        mdch.setIterations(iterations);
54
        mdch.setSaltLength(saltLength);
55
        mdch.setSaltLength(saltLength);
56
        verifier.setAlgorithm(digest);
55
        String storedCredential = mdch.mutate(PWD);
57
        String storedCredential = mdch.mutate(PWD);
56
        Assert.assertTrue(mdch.matches(PWD, storedCredential));
58
        Assert.assertTrue(verifier.matches(PWD, storedCredential));
57
    }
59
    }
58
}
60
}
(-)a/test/org/apache/catalina/realm/TestSecretKeyCredentialHandler.java (-15 / +36 lines)
Lines 23-51 import org.junit.Test; Link Here
23
23
24
public class TestSecretKeyCredentialHandler {
24
public class TestSecretKeyCredentialHandler {
25
25
26
    private static final String[] ALGORITHMS =
26
    private static final String[] ALGORITHMS = { "PBKDF2WithHmacSHA1", "PBEWithMD5AndDES" };
27
            new String[] {"PBKDF2WithHmacSHA1", "PBEWithMD5AndDES"};
27
    private static final String[] PASSWORDS = { "password", "$!&#%!%@$#@*^$%&%%#!!*%$%&#@!^" };
28
28
    private static final int[] KEYLENGTHS = { 8, 111, 256 };
29
    private static final String PWD = "password";
29
    private static final int[] SALTLENGTHS = { 1, 7, 12, 20 };
30
    private static final int[] ITERATIONS = { 1, 2111, 10000 };
30
31
31
    @Test
32
    @Test
32
    public void testGeneral() throws Exception {
33
    public void testGeneral() throws Exception {
33
        for (String digest : ALGORITHMS) {
34
        for (String digest : ALGORITHMS)
34
            for (int saltLength = 1; saltLength < 20; saltLength++) {
35
            for (String password : PASSWORDS)
35
                for (int iterations = 1; iterations < 10000; iterations += 1000)
36
                for (int saltLength : SALTLENGTHS)
36
                    doTest(digest, saltLength, iterations);
37
                    for (int iterations : ITERATIONS)
37
            }
38
                        for (int keyLength : KEYLENGTHS)
38
        }
39
                            doTest(password, digest, saltLength, iterations, keyLength);
40
    }
41
42
    @Test(expected = IllegalArgumentException.class)
43
    public void testZeroSalt() throws NoSuchAlgorithmException {
44
        doTest(PASSWORDS[0], ALGORITHMS[0], 0, ITERATIONS[0], KEYLENGTHS[0]);
45
    }
46
47
    @Test(expected = IllegalArgumentException.class)
48
    public void testZeroIterations() throws NoSuchAlgorithmException {
49
        doTest(PASSWORDS[0], ALGORITHMS[0], SALTLENGTHS[0], 0, KEYLENGTHS[0]);
50
    }
51
52
    @Test(expected = IllegalArgumentException.class)
53
    public void testZeroKeyLength() throws NoSuchAlgorithmException {
54
        doTest(PASSWORDS[0], ALGORITHMS[0], SALTLENGTHS[0], ITERATIONS[0], 0);
39
    }
55
    }
40
56
41
    private void doTest(String digest, int saltLength, int iterations)
57
    private void doTest(String password, String digest, int saltLength, int iterations,
42
            throws NoSuchAlgorithmException {
58
            int keyLength) throws NoSuchAlgorithmException {
43
        SecretKeyCredentialHandler pbech = new SecretKeyCredentialHandler();
59
        SecretKeyCredentialHandler pbech = new SecretKeyCredentialHandler();
60
        SecretKeyCredentialHandler verifier = new SecretKeyCredentialHandler();
44
        pbech.setAlgorithm(digest);
61
        pbech.setAlgorithm(digest);
45
        pbech.setIterations(iterations);
62
        pbech.setIterations(iterations);
46
        pbech.setSaltLength(saltLength);
63
        pbech.setSaltLength(saltLength);
47
        String storedCredential = pbech.mutate(PWD);
64
        pbech.setKeyLength(keyLength);
48
        Assert.assertTrue("[" + digest + "] [" + saltLength + "] [" + iterations + "] [" + PWD +
65
        verifier.setAlgorithm(digest);
49
                "] [" + storedCredential +"]", pbech.matches(PWD, storedCredential));
66
        String storedCredential = pbech.mutate(password);
67
        Assert.assertTrue(
68
                "[" + digest + "] [" + saltLength + "] [" + iterations + "] [" + keyLength + "] ["
69
                        + password + "] [" + storedCredential + "]",
70
                verifier.matches(password, storedCredential));
50
    }
71
    }
51
}
72
}

Return to bug 60446