CR-4097 Big code cleanup of some storage schemes.
PBKDF2PasswordStorageScheme.java, PKCS5S2PasswordStorageScheme.java:
Fixed a bug in PBKF2 + PKCS5S2 encodeOffline() methods which did not know how to deal with a byte[]. The right way was to wrap it in a ByteString like SaltedSHA1PasswordStorageScheme was already doing. BTW these encodeOffline() methods are never called from production code.
Did more code factorization.
Removed dead code in both with plainPlusSalt local variable which was not used for anything.
Fixed a few bugs in PKCS5S2 where locks where not properly taken (or carefully avoided?).
Made both PBKF2 + PKCS5S2 code look very similar now.
PBKDF2PasswordStorageSchemeTestCase.java, PKCS5S2PasswordStorageSchemeTestCase.java, PasswordStorageSchemeTestCase.java, SaltedSHA1PasswordStorageSchemeTestCase.java, SaltedSHA256PasswordStorageSchemeTestCase.java, SaltedSHA384PasswordStorageSchemeTestCase.java, SaltedSHA512PasswordStorageSchemeTestCase.java:
Removed dead code.
CryptPasswordStorageSchemeTestCase.java:
Made it reuse more code from PasswordStorageSchemeTestCase.
| | |
| | | /** The current configuration for this storage scheme. */ |
| | | private volatile PBKDF2PasswordStorageSchemeCfg config; |
| | | |
| | | |
| | | /** |
| | | * Creates a new instance of this password storage scheme. Note that no |
| | | * initialization should be performed here, as all initialization should be |
| | |
| | | byte[] saltBytes = new byte[NUM_SALT_BYTES]; |
| | | int iterations = config.getPBKDF2Iterations(); |
| | | |
| | | byte[] digestBytes = getDigestBytes(plaintext, saltBytes, iterations); |
| | | // Append the salt to the hashed value and base64-the whole thing. |
| | | byte[] hashPlusSalt = new byte[digestBytes.length + NUM_SALT_BYTES]; |
| | | |
| | | System.arraycopy(digestBytes, 0, hashPlusSalt, 0, digestBytes.length); |
| | | System.arraycopy(saltBytes, 0, hashPlusSalt, digestBytes.length, |
| | | NUM_SALT_BYTES); |
| | | byte[] digestBytes = encodeWithRandomSalt(plaintext, saltBytes, iterations); |
| | | byte[] hashPlusSalt = concatenateHashPlusSalt(saltBytes, digestBytes); |
| | | |
| | | return ByteString.valueOf(iterations + ":" + Base64.encode(hashPlusSalt)); |
| | | } |
| | |
| | | // Base64-decode the remaining value and take the last 8 bytes as the salt. |
| | | try |
| | | { |
| | | String stored = storedPassword.toString(); |
| | | int pos = stored.indexOf(':'); |
| | | final String stored = storedPassword.toString(); |
| | | final int pos = stored.indexOf(':'); |
| | | if (pos == -1) |
| | | { |
| | | throw new Exception(); |
| | |
| | | } |
| | | } |
| | | |
| | | private boolean encodeAndMatch(ByteSequence plaintextPassword, |
| | | final byte[] saltBytes, byte[] digestBytes, int iterations) |
| | | { |
| | | // Use the salt to generate a digest based on the provided plain-text value. |
| | | int plainBytesLength = plaintextPassword.length(); |
| | | byte[] plainPlusSalt = new byte[plainBytesLength + saltBytes.length]; |
| | | plaintextPassword.copyTo(plainPlusSalt); |
| | | System.arraycopy(saltBytes, 0, plainPlusSalt, plainBytesLength, saltBytes.length); |
| | | |
| | | |
| | | char[] plaintextChars = null; |
| | | synchronized (factoryLock) |
| | | { |
| | | try |
| | | { |
| | | plaintextChars = plaintextPassword.toString().toCharArray(); |
| | | KeySpec spec = new PBEKeySpec( |
| | | plaintextChars, saltBytes, |
| | | iterations, SHA1_LENGTH * 8); |
| | | final byte[] userDigestBytes = factory.generateSecret(spec).getEncoded(); |
| | | return Arrays.equals(digestBytes, userDigestBytes); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | logger.traceException(e); |
| | | return false; |
| | | } |
| | | finally |
| | | { |
| | | if (plaintextChars != null) |
| | | { |
| | | Arrays.fill(plaintextChars, '0'); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean supportsAuthPasswordSyntax() |
| | |
| | | { |
| | | byte[] saltBytes = new byte[NUM_SALT_BYTES]; |
| | | int iterations = config.getPBKDF2Iterations(); |
| | | byte[] digestBytes = getDigestBytes(plaintext, saltBytes, iterations); |
| | | byte[] digestBytes = encodeWithRandomSalt(plaintext, saltBytes, iterations); |
| | | |
| | | // Encode and return the value. |
| | | return ByteString.valueOf(AUTH_PASSWORD_SCHEME_NAME_PBKDF2 + '$' |
| | |
| | | + Base64.encode(digestBytes)); |
| | | } |
| | | |
| | | private byte[] getDigestBytes(ByteSequence plaintext, byte[] saltBytes, |
| | | int iterations) throws DirectoryException |
| | | { |
| | | char[] plaintextChars = null; |
| | | synchronized (factoryLock) |
| | | { |
| | | try |
| | | { |
| | | random.nextBytes(saltBytes); |
| | | |
| | | plaintextChars = plaintext.toString().toCharArray(); |
| | | KeySpec spec = new PBEKeySpec( |
| | | plaintextChars, saltBytes, |
| | | iterations, SHA1_LENGTH * 8); |
| | | return factory.generateSecret(spec).getEncoded(); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | logger.traceException(e); |
| | | |
| | | LocalizableMessage message = ERR_PWSCHEME_CANNOT_ENCODE_PASSWORD.get( |
| | | CLASS_NAME, getExceptionMessage(e)); |
| | | throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), |
| | | message, e); |
| | | } |
| | | finally |
| | | { |
| | | if (plaintextChars != null) |
| | | { |
| | | Arrays.fill(plaintextChars, '0'); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | public boolean authPasswordMatches(ByteSequence plaintextPassword, |
| | |
| | | * user password). |
| | | * |
| | | * @param passwordBytes The bytes that make up the clear-text password. |
| | | * |
| | | * @return The encoded password string, including the scheme name in curly |
| | | * braces. |
| | | * |
| | | * @throws DirectoryException If a problem occurs during processing. |
| | | */ |
| | | public static String encodeOffline(byte[] passwordBytes) |
| | |
| | | byte[] saltBytes = new byte[NUM_SALT_BYTES]; |
| | | int iterations = 10000; |
| | | |
| | | byte[] digestBytes = getDigestBytes(passwordBytes, saltBytes, iterations); |
| | | // Append the salt to the hashed value and base64-the whole thing. |
| | | byte[] hashPlusSalt = new byte[digestBytes.length + NUM_SALT_BYTES]; |
| | | final ByteString password = ByteString.wrap(passwordBytes); |
| | | byte[] digestBytes = encodeWithRandomSalt(password, saltBytes, iterations); |
| | | byte[] hashPlusSalt = concatenateHashPlusSalt(saltBytes, digestBytes); |
| | | |
| | | System.arraycopy(digestBytes, 0, hashPlusSalt, 0, digestBytes.length); |
| | | System.arraycopy(saltBytes, 0, hashPlusSalt, digestBytes.length, |
| | | NUM_SALT_BYTES); |
| | | |
| | | return '{' + STORAGE_SCHEME_NAME_PBKDF2 + '}' + iterations + ':' + |
| | | Base64.encode(hashPlusSalt); |
| | | return '{' + STORAGE_SCHEME_NAME_PBKDF2 + '}' + iterations + ':' |
| | | + Base64.encode(hashPlusSalt); |
| | | } |
| | | |
| | | private static byte[] getDigestBytes(byte[] plaintext, byte[] saltBytes, |
| | | private static byte[] encodeWithRandomSalt(ByteString plaintext, byte[] saltBytes, |
| | | int iterations) throws DirectoryException |
| | | { |
| | | char[] plaintextChars = null; |
| | | try |
| | | { |
| | | SecureRandom.getInstance(SECURE_PRNG_SHA1).nextBytes(saltBytes); |
| | | |
| | | plaintextChars = plaintext.toString().toCharArray(); |
| | | KeySpec spec = new PBEKeySpec( |
| | | plaintextChars, saltBytes, |
| | | iterations, SHA1_LENGTH * 8); |
| | | return SecretKeyFactory |
| | | .getInstance(MESSAGE_DIGEST_ALGORITHM_PBKDF2) |
| | | .generateSecret(spec).getEncoded(); |
| | | final SecureRandom random = SecureRandom.getInstance(SECURE_PRNG_SHA1); |
| | | final SecretKeyFactory factory = SecretKeyFactory.getInstance(MESSAGE_DIGEST_ALGORITHM_PBKDF2); |
| | | return encodeWithRandomSalt(plaintext, saltBytes, iterations, random, factory); |
| | | } |
| | | catch (DirectoryException e) |
| | | { |
| | | throw e; |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | logger.traceException(e); |
| | | throw cannotEncodePassword(e); |
| | | } |
| | | } |
| | | |
| | | LocalizableMessage message = ERR_PWSCHEME_CANNOT_ENCODE_PASSWORD.get( |
| | | CLASS_NAME, getExceptionMessage(e)); |
| | | throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), |
| | | message, e); |
| | | private static byte[] encodeWithSalt(ByteSequence plaintext, byte[] saltBytes, |
| | | int iterations, final SecretKeyFactory factory) throws DirectoryException |
| | | { |
| | | final char[] plaintextChars = plaintext.toString().toCharArray(); |
| | | try |
| | | { |
| | | KeySpec spec = |
| | | new PBEKeySpec(plaintextChars, saltBytes, iterations, SHA1_LENGTH * 8); |
| | | return factory.generateSecret(spec).getEncoded(); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | throw cannotEncodePassword(e); |
| | | } |
| | | finally |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | private boolean encodeAndMatch(ByteSequence plaintext, byte[] saltBytes, |
| | | byte[] digestBytes, int iterations) |
| | | { |
| | | synchronized (factoryLock) |
| | | { |
| | | try |
| | | { |
| | | final byte[] userDigestBytes = |
| | | encodeWithSalt(plaintext, saltBytes, iterations, factory); |
| | | return Arrays.equals(digestBytes, userDigestBytes); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | |
| | | private byte[] encodeWithRandomSalt(ByteSequence plaintext, byte[] saltBytes, |
| | | int iterations) throws DirectoryException |
| | | { |
| | | synchronized (factoryLock) |
| | | { |
| | | return encodeWithRandomSalt(plaintext, saltBytes, iterations, random, factory); |
| | | } |
| | | } |
| | | |
| | | private static byte[] encodeWithRandomSalt(ByteSequence plaintext, byte[] saltBytes, |
| | | int iterations, SecureRandom random, final SecretKeyFactory factory) throws DirectoryException |
| | | { |
| | | random.nextBytes(saltBytes); |
| | | return encodeWithSalt(plaintext, saltBytes, iterations, factory); |
| | | } |
| | | |
| | | private static DirectoryException cannotEncodePassword(Exception e) |
| | | { |
| | | logger.traceException(e); |
| | | |
| | | LocalizableMessage message = ERR_PWSCHEME_CANNOT_ENCODE_PASSWORD.get(CLASS_NAME, getExceptionMessage(e)); |
| | | return new DirectoryException(DirectoryServer.getServerErrorResultCode(), message, e); |
| | | } |
| | | |
| | | private static byte[] concatenateHashPlusSalt(byte[] saltBytes, byte[] digestBytes) { |
| | | final byte[] hashPlusSalt = new byte[digestBytes.length + NUM_SALT_BYTES]; |
| | | System.arraycopy(digestBytes, 0, hashPlusSalt, 0, digestBytes.length); |
| | | System.arraycopy(saltBytes, 0, hashPlusSalt, digestBytes.length, NUM_SALT_BYTES); |
| | | return hashPlusSalt; |
| | | } |
| | | |
| | | } |
| | |
| | | /** The secure random number generator to use to generate the salt values. */ |
| | | private SecureRandom random; |
| | | |
| | | |
| | | /** |
| | | * Creates a new instance of this password storage scheme. Note that no |
| | | * initialization should be performed here, as all initialization should be |
| | |
| | | throws DirectoryException |
| | | { |
| | | byte[] saltBytes = new byte[NUM_SALT_BYTES]; |
| | | byte[] digestBytes = createRandomSaltAndEncode(plaintext, saltBytes); |
| | | // Append the hashed value to the salt and base64-the whole thing. |
| | | byte[] digestBytes = encodeWithRandomSalt(plaintext, saltBytes); |
| | | byte[] hashPlusSalt = concatenateSaltPlusHash(saltBytes, digestBytes); |
| | | |
| | | return ByteString.valueOf(Base64.encode(hashPlusSalt)); |
| | |
| | | try |
| | | { |
| | | String stored = storedPassword.toString(); |
| | | |
| | | byte[] decodedBytes = Base64.decode(stored); |
| | | |
| | | if (decodedBytes.length != NUM_SALT_BYTES + SHA1_LENGTH) |
| | |
| | | } |
| | | |
| | | final int saltLength = NUM_SALT_BYTES; |
| | | byte[] saltBytes = new byte[saltLength]; |
| | | byte[] digestBytes = new byte[SHA1_LENGTH]; |
| | | final byte[] digestBytes = new byte[SHA1_LENGTH]; |
| | | final byte[] saltBytes = new byte[saltLength]; |
| | | System.arraycopy(decodedBytes, 0, saltBytes, 0, saltLength); |
| | | System.arraycopy(decodedBytes, saltLength, digestBytes, 0, SHA1_LENGTH); |
| | | return encodeAndMatch(plaintextPassword, saltBytes, digestBytes, iterations); |
| | |
| | | throws DirectoryException |
| | | { |
| | | byte[] saltBytes = new byte[NUM_SALT_BYTES]; |
| | | byte[] digestBytes = createRandomSaltAndEncode(plaintext, saltBytes); |
| | | byte[] digestBytes = encodeWithRandomSalt(plaintext, saltBytes); |
| | | // Encode and return the value. |
| | | return ByteString.valueOf(AUTH_PASSWORD_SCHEME_NAME_PKCS5S2 + '$' |
| | | + iterations + ':' + Base64.encode(saltBytes) + '$' |
| | |
| | | int pos = authInfo.indexOf(':'); |
| | | if (pos == -1) |
| | | { |
| | | return false; |
| | | throw new Exception(); |
| | | } |
| | | int iterations = Integer.parseInt(authInfo.substring(0, pos)); |
| | | byte[] saltBytes = Base64.decode(authInfo.substring(pos + 1)); |
| | |
| | | * user password). |
| | | * |
| | | * @param passwordBytes The bytes that make up the clear-text password. |
| | | * |
| | | * @return The encoded password string, including the scheme name in curly |
| | | * braces. |
| | | * |
| | | * @throws DirectoryException If a problem occurs during processing. |
| | | */ |
| | | public static String encodeOffline(byte[] passwordBytes) |
| | | throws DirectoryException |
| | | { |
| | | byte[] saltBytes = new byte[NUM_SALT_BYTES]; |
| | | byte[] digestBytes; |
| | | |
| | | try |
| | | { |
| | | SecureRandom.getInstance(SECURE_PRNG_SHA1).nextBytes(saltBytes); |
| | | |
| | | char[] plaintextChars = Arrays.toString(passwordBytes).toCharArray(); |
| | | KeySpec spec = new PBEKeySpec(plaintextChars, saltBytes,iterations, |
| | | SHA1_LENGTH * 8); |
| | | digestBytes = SecretKeyFactory |
| | | .getInstance(MESSAGE_DIGEST_ALGORITHM_PBKDF2) |
| | | .generateSecret(spec).getEncoded(); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | logger.traceException(e); |
| | | LocalizableMessage message = ERR_PWSCHEME_CANNOT_ENCODE_PASSWORD.get( |
| | | CLASS_NAME, getExceptionMessage(e)); |
| | | throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), |
| | | message, e); |
| | | } |
| | | |
| | | // Append the hashed value to the salt and base64-the whole thing. |
| | | byte[] digestBytes = encodeWithRandomSalt(ByteString.wrap(passwordBytes), saltBytes); |
| | | byte[] hashPlusSalt = concatenateSaltPlusHash(saltBytes, digestBytes); |
| | | |
| | | return '{' + STORAGE_SCHEME_NAME_PKCS5S2 + '}' + |
| | | Base64.encode(hashPlusSalt); |
| | | } |
| | | |
| | | |
| | | private boolean encodeAndMatch(ByteSequence plaintext, |
| | | byte[] saltBytes, byte[] digestBytes, int iterations) |
| | | private static byte[] encodeWithRandomSalt(ByteString plaintext, byte[] saltBytes) |
| | | throws DirectoryException |
| | | { |
| | | try |
| | | { |
| | | byte[] userDigestBytes = encodeWithSalt(plaintext, saltBytes, iterations); |
| | | return Arrays.equals(digestBytes, userDigestBytes); |
| | | final SecureRandom random = SecureRandom.getInstance(SECURE_PRNG_SHA1); |
| | | final SecretKeyFactory factory = SecretKeyFactory.getInstance(MESSAGE_DIGEST_ALGORITHM_PBKDF2); |
| | | return encodeWithRandomSalt(plaintext, saltBytes, random, factory); |
| | | } |
| | | catch (DirectoryException e) |
| | | { |
| | | throw e; |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | return false; |
| | | throw cannotEncodePassword(e); |
| | | } |
| | | } |
| | | |
| | | |
| | | private byte[] createRandomSaltAndEncode(ByteSequence plaintext, byte[] saltBytes) throws DirectoryException { |
| | | synchronized(factoryLock) |
| | | private static byte[] encodeWithSalt(ByteSequence plaintext, byte[] saltBytes, |
| | | int iterations, final SecretKeyFactory factory) throws DirectoryException |
| | | { |
| | | random.nextBytes(saltBytes); |
| | | return encodeWithSalt(plaintext, saltBytes, iterations); |
| | | } |
| | | } |
| | | |
| | | private byte[] encodeWithSalt(ByteSequence plaintext, byte[] saltBytes, int iterations) throws DirectoryException { |
| | | char[] plaintextChars = null; |
| | | final char[] plaintextChars = plaintext.toString().toCharArray(); |
| | | try |
| | | { |
| | | plaintextChars = plaintext.toString().toCharArray(); |
| | | KeySpec spec = new PBEKeySpec( |
| | | plaintextChars, saltBytes, |
| | | iterations, SHA1_LENGTH * 8); |
| | | KeySpec spec = |
| | | new PBEKeySpec(plaintextChars, saltBytes, iterations, SHA1_LENGTH * 8); |
| | | return factory.generateSecret(spec).getEncoded(); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | logger.traceException(e); |
| | | |
| | | LocalizableMessage message = ERR_PWSCHEME_CANNOT_ENCODE_PASSWORD.get( |
| | | CLASS_NAME, getExceptionMessage(e)); |
| | | throw new DirectoryException(DirectoryServer.getServerErrorResultCode(), |
| | | message, e); |
| | | throw cannotEncodePassword(e); |
| | | } |
| | | finally |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | private static byte[] concatenateSaltPlusHash(byte[] saltBytes, byte[] digestBytes) { |
| | | byte[] hashPlusSalt = new byte[digestBytes.length + NUM_SALT_BYTES]; |
| | | private boolean encodeAndMatch(ByteSequence plaintext, byte[] saltBytes, |
| | | byte[] digestBytes, int iterations) |
| | | { |
| | | synchronized (factoryLock) |
| | | { |
| | | try |
| | | { |
| | | final byte[] userDigestBytes = |
| | | encodeWithSalt(plaintext, saltBytes, iterations, factory); |
| | | return Arrays.equals(digestBytes, userDigestBytes); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | return false; |
| | | } |
| | | } |
| | | } |
| | | |
| | | private byte[] encodeWithRandomSalt(ByteSequence plaintext, byte[] saltBytes) |
| | | throws DirectoryException |
| | | { |
| | | synchronized (factoryLock) |
| | | { |
| | | return encodeWithRandomSalt(plaintext, saltBytes, random, factory); |
| | | } |
| | | } |
| | | |
| | | private static byte[] encodeWithRandomSalt(ByteSequence plaintext, byte[] saltBytes, |
| | | SecureRandom random, final SecretKeyFactory factory) throws DirectoryException |
| | | { |
| | | random.nextBytes(saltBytes); |
| | | return encodeWithSalt(plaintext, saltBytes, iterations, factory); |
| | | } |
| | | |
| | | private static DirectoryException cannotEncodePassword(Exception e) |
| | | { |
| | | logger.traceException(e); |
| | | |
| | | LocalizableMessage message = ERR_PWSCHEME_CANNOT_ENCODE_PASSWORD.get(CLASS_NAME, getExceptionMessage(e)); |
| | | return new DirectoryException(DirectoryServer.getServerErrorResultCode(), message, e); |
| | | } |
| | | |
| | | private static byte[] concatenateSaltPlusHash(byte[] saltBytes, byte[] digestBytes) { |
| | | final byte[] hashPlusSalt = new byte[digestBytes.length + NUM_SALT_BYTES]; |
| | | System.arraycopy(saltBytes, 0, hashPlusSalt, 0, NUM_SALT_BYTES); |
| | | System.arraycopy(digestBytes, 0, hashPlusSalt, NUM_SALT_BYTES, |
| | | digestBytes.length); |
| | | System.arraycopy(digestBytes, 0, hashPlusSalt, NUM_SALT_BYTES, digestBytes.length); |
| | | return hashPlusSalt; |
| | | } |
| | | |
| | |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | | import static org.testng.Assert.assertEquals; |
| | | import static org.testng.Assert.assertFalse; |
| | | import static org.testng.Assert.assertNotNull; |
| | | import static org.testng.Assert.assertTrue; |
| | | |
| | | import java.util.ArrayList; |
| | | |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.opends.server.TestCaseUtils; |
| | | import org.opends.server.admin.server.AdminTestCaseUtils; |
| | | import org.opends.server.admin.std.meta.CryptPasswordStorageSchemeCfgDefn; |
| | | import org.opends.server.admin.std.server.CryptPasswordStorageSchemeCfg; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.core.ModifyOperation; |
| | | import org.opends.server.core.PasswordPolicy; |
| | | import org.opends.server.protocols.internal.InternalClientConnection; |
| | | import org.opends.server.schema.AuthPasswordSyntax; |
| | | import org.opends.server.schema.UserPasswordSyntax; |
| | | import org.opends.server.types.Attributes; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | import org.opends.server.types.DN; |
| | | import org.opends.server.types.DirectoryException; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.Modification; |
| | | import org.forgerock.opendj.ldap.ModificationType; |
| | | import org.forgerock.opendj.ldap.ResultCode; |
| | | import org.testng.annotations.BeforeClass; |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import static org.opends.server.extensions.PasswordStorageSchemeTestCase.*; |
| | | |
| | | |
| | | /** |
| | | * A set of test cases for the crypt password storage scheme. |
| | | */ |
| | | @SuppressWarnings("javadoc") |
| | | public class CryptPasswordStorageSchemeTestCase |
| | | extends ExtensionsTestCase |
| | | { |
| | | |
| | | // Names of all the crypt algorithms we want to test. |
| | | private static final String[] names = { "unix", "md5", "sha256", "sha512" }; |
| | | |
| | |
| | | * Ensures that the Directory Server is started before running any of these |
| | | * tests. |
| | | */ |
| | | @BeforeClass() |
| | | @BeforeClass |
| | | public void startServer() throws Exception |
| | | { |
| | | TestCaseUtils.startServer(); |
| | |
| | | @DataProvider(name = "testPasswords") |
| | | public Object[][] getTestPasswords() |
| | | { |
| | | return new Object[][] |
| | | { |
| | | new Object[] { ByteString.empty() }, |
| | | new Object[] { ByteString.valueOf("") }, |
| | | new Object[] { ByteString.valueOf("\u0000") }, |
| | | new Object[] { ByteString.valueOf("\t") }, |
| | | new Object[] { ByteString.valueOf("\n") }, |
| | | new Object[] { ByteString.valueOf("\r\n") }, |
| | | new Object[] { ByteString.valueOf(" ") }, |
| | | new Object[] { ByteString.valueOf("Test1\tTest2\tTest3") }, |
| | | new Object[] { ByteString.valueOf("Test1\nTest2\nTest3") }, |
| | | new Object[] { ByteString.valueOf("Test1\r\nTest2\r\nTest3") }, |
| | | new Object[] { ByteString.valueOf("a") }, |
| | | new Object[] { ByteString.valueOf("ab") }, |
| | | new Object[] { ByteString.valueOf("abc") }, |
| | | new Object[] { ByteString.valueOf("abcd") }, |
| | | new Object[] { ByteString.valueOf("abcde") }, |
| | | new Object[] { ByteString.valueOf("abcdef") }, |
| | | new Object[] { ByteString.valueOf("abcdefg") }, |
| | | new Object[] { ByteString.valueOf("abcdefgh") }, |
| | | new Object[] { ByteString.valueOf("The Quick Brown Fox Jumps Over " + |
| | | "The Lazy Dog") }, |
| | | new Object[] { ByteString.valueOf("\u00BFD\u00F3nde est\u00E1 el " + |
| | | "ba\u00F1o?") } |
| | | }; |
| | | return getTestPasswordsStatic(); |
| | | } |
| | | |
| | | |
| | |
| | | * provided password, and ensures that the encoded value is correct. |
| | | * |
| | | * @param plaintext The plain-text version of the password to encode. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test(dataProvider = "testPasswords") |
| | |
| | | { |
| | | for (String name : names) |
| | | { |
| | | CryptPasswordStorageScheme scheme = getScheme(name); |
| | | assertNotNull(scheme); |
| | | assertNotNull(scheme.getStorageSchemeName()); |
| | | |
| | | ByteString encodedPassword = scheme.encodePassword(plaintext); |
| | | assertNotNull(encodedPassword); |
| | | assertTrue(scheme.passwordMatches(plaintext, encodedPassword)); |
| | | assertFalse(scheme.passwordMatches(plaintext, |
| | | ByteString.valueOf("garbage"))); |
| | | |
| | | ByteString schemeEncodedPassword = |
| | | scheme.encodePasswordWithScheme(plaintext); |
| | | String[] pwComponents = UserPasswordSyntax.decodeUserPassword( |
| | | schemeEncodedPassword.toString()); |
| | | assertNotNull(pwComponents); |
| | | |
| | | |
| | | if (scheme.supportsAuthPasswordSyntax()) |
| | | { |
| | | assertNotNull(scheme.getAuthPasswordSchemeName()); |
| | | ByteString encodedAuthPassword = scheme.encodeAuthPassword(plaintext); |
| | | StringBuilder[] authPWComponents = |
| | | AuthPasswordSyntax.decodeAuthPassword( |
| | | encodedAuthPassword.toString()); |
| | | assertTrue(scheme.authPasswordMatches(plaintext, |
| | | authPWComponents[1].toString(), |
| | | authPWComponents[2].toString())); |
| | | assertFalse(scheme.authPasswordMatches(plaintext, ",", "foo")); |
| | | assertFalse(scheme.authPasswordMatches(plaintext, "foo", ",")); |
| | | } |
| | | else |
| | | { |
| | | try |
| | | { |
| | | scheme.encodeAuthPassword(plaintext); |
| | | throw new Exception("Expected encodedAuthPassword to fail for scheme " + |
| | | scheme.getStorageSchemeName() + |
| | | " because it doesn't support auth passwords."); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | // This was expected. |
| | | } |
| | | |
| | | assertFalse(scheme.authPasswordMatches(plaintext, "foo", "bar")); |
| | | } |
| | | |
| | | |
| | | if (scheme.isReversible()) |
| | | { |
| | | assertEquals(scheme.getPlaintextValue(encodedPassword), plaintext); |
| | | } |
| | | else |
| | | { |
| | | try |
| | | { |
| | | scheme.getPlaintextValue(encodedPassword); |
| | | throw new Exception("Expected getPlaintextValue to fail for scheme " + |
| | | scheme.getStorageSchemeName() + |
| | | " because it is not reversible."); |
| | | } |
| | | catch (DirectoryException de) |
| | | { |
| | | // This was expected. |
| | | testStorageScheme(plaintext, getScheme(name)); |
| | | } |
| | | } |
| | | |
| | | scheme.isStorageSchemeSecure(); |
| | | |
| | | } |
| | | } |
| | | |
| | | |
| | | |
| | | @DataProvider |
| | | public Object[][] passwordsForBinding() |
| | | { |
| | | return new Object[][] |
| | | { |
| | | // In the case of a clear-text password, these values will be shoved |
| | | // un-excaped into an LDIF file, so make sure they don't include \n |
| | | // or other characters that will cause LDIF parsing errors. |
| | | // We really don't need many test cases here, since that functionality |
| | | // is tested above. |
| | | new Object[] { ByteString.valueOf("a") }, |
| | | new Object[] { ByteString.valueOf("abcdefgh") }, |
| | | new Object[] { ByteString.valueOf("abcdefghi") }, |
| | | }; |
| | | return PasswordStorageSchemeTestCase.passwordsForBinding(); |
| | | } |
| | | |
| | | |
| | |
| | | { |
| | | for (String name: names) |
| | | { |
| | | // Start/clear-out the memory backend |
| | | TestCaseUtils.initializeTestBackend(true); |
| | | |
| | | setAllowPreencodedPasswords(true); |
| | | |
| | | CryptPasswordStorageScheme scheme = getScheme(name); |
| | | ByteString schemeEncodedPassword = |
| | | scheme.encodePasswordWithScheme(plainPassword); |
| | | |
| | | // |
| | | // This code creates a user with the encoded password, |
| | | // and then verifies that they can bind with the raw password. |
| | | // |
| | | |
| | | Entry userEntry = TestCaseUtils.makeEntry( |
| | | "dn: uid=test.user,o=test", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: test.user", |
| | | "givenName: Test", |
| | | "sn: User", |
| | | "cn: Test User", |
| | | "ds-privilege-name: bypass-acl", |
| | | "userPassword: " + schemeEncodedPassword.toString()); |
| | | |
| | | // Add the entry |
| | | TestCaseUtils.addEntry(userEntry); |
| | | |
| | | assertTrue(TestCaseUtils.canBind("uid=test.user,o=test", |
| | | plainPassword.toString()), |
| | | "Failed to bind when pre-encoded password = \"" + |
| | | schemeEncodedPassword.toString() + "\" and " + |
| | | "plaintext password = \"" + |
| | | plainPassword.toString() + "\""); |
| | | testSettingEncodedPassword(plainPassword, getScheme(name)); |
| | | } |
| | | } |
| | | |
| | | |
| | | /** |
| | | * Sets whether or not to allow pre-encoded password values for the |
| | | * current password storage scheme and returns the previous value so that |
| | | * it can be restored. |
| | | * |
| | | * @param allowPreencoded whether or not to allow pre-encoded passwords |
| | | * @return the previous value for the allow preencoded passwords |
| | | */ |
| | | private boolean setAllowPreencodedPasswords(boolean allowPreencoded) |
| | | throws Exception |
| | | { |
| | | // This code was borrowed from |
| | | // PasswordPolicyTestCase.testAllowPreEncodedPasswordsAuth |
| | | boolean previousValue = false; |
| | | try { |
| | | DN dn = DN.valueOf("cn=Default Password Policy,cn=Password Policies,cn=config"); |
| | | PasswordPolicy p = (PasswordPolicy) DirectoryServer.getAuthenticationPolicy(dn); |
| | | previousValue = p.isAllowPreEncodedPasswords(); |
| | | |
| | | String attr = "ds-cfg-allow-pre-encoded-passwords"; |
| | | |
| | | ArrayList<Modification> mods = new ArrayList<Modification>(); |
| | | mods.add(new Modification(ModificationType.REPLACE, |
| | | Attributes.create(attr, String.valueOf(allowPreencoded)))); |
| | | |
| | | InternalClientConnection conn = |
| | | InternalClientConnection.getRootConnection(); |
| | | ModifyOperation modifyOperation = conn.processModify(dn, mods); |
| | | assertEquals(modifyOperation.getResultCode(), ResultCode.SUCCESS); |
| | | |
| | | p = (PasswordPolicy) DirectoryServer.getAuthenticationPolicy(dn); |
| | | assertEquals(p.isAllowPreEncodedPasswords(), allowPreencoded); |
| | | } catch (Exception e) { |
| | | System.err.println("Failed to set ds-cfg-allow-pre-encoded-passwords " + |
| | | " to " + allowPreencoded); |
| | | e.printStackTrace(); |
| | | throw e; |
| | | } |
| | | |
| | | return previousValue; |
| | | } |
| | | |
| | | /** |
| | | * Retrieves a set of passwords (plain and variously hashed) that may |
| | | * be used to test the different Unix "crypt" algorithms used by the Crypt |
| | |
| | | * may be used to test the different algorithms used by the Crypt |
| | | * password storage scheme. |
| | | */ |
| | | |
| | | @DataProvider(name = "testCryptPasswords") |
| | | public Object[][] getTestCryptPasswords() |
| | | throws Exception |
| | |
| | | String plaintextPassword, |
| | | String encodedPassword) throws Exception |
| | | { |
| | | // Start/clear-out the memory backend |
| | | TestCaseUtils.initializeTestBackend(true); |
| | | |
| | | boolean allowPreencodedDefault = setAllowPreencodedPasswords(true); |
| | | |
| | | try { |
| | | |
| | | Entry userEntry = TestCaseUtils.makeEntry( |
| | | "dn: uid=testCrypt.user,o=test", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: testCrypt.user", |
| | | "givenName: TestCrypt", |
| | | "sn: User", |
| | | "cn: TestCrypt User", |
| | | "userPassword: " + encodedPassword); |
| | | |
| | | |
| | | // Add the entry |
| | | TestCaseUtils.addEntry(userEntry); |
| | | |
| | | assertTrue(TestCaseUtils.canBind("uid=testCrypt.user,o=test", |
| | | plaintextPassword), |
| | | "Failed to bind when pre-encoded password = \"" + |
| | | encodedPassword + "\" and " + |
| | | "plaintext password = \"" + |
| | | plaintextPassword + "\"" ); |
| | | } finally { |
| | | setAllowPreencodedPasswords(allowPreencodedDefault); |
| | | } |
| | | testAuthPasswords("TestCrypt", plaintextPassword, encodedPassword); |
| | | } |
| | | |
| | | /** |
| | |
| | | import org.opends.server.admin.std.meta.PBKDF2PasswordStorageSchemeCfgDefn; |
| | | import org.opends.server.admin.std.server.PBKDF2PasswordStorageSchemeCfg; |
| | | import org.opends.server.api.PasswordStorageScheme; |
| | | import org.opends.server.types.DirectoryException; |
| | | import org.testng.annotations.DataProvider; |
| | | |
| | | /** |
| | | * A set of test cases for the PBKDF2 password storage scheme. |
| | | */ |
| | | @SuppressWarnings("javadoc") |
| | | public class PBKDF2PasswordStorageSchemeTestCase |
| | | extends PasswordStorageSchemeTestCase |
| | | { |
| | |
| | | return scheme; |
| | | } |
| | | |
| | | @Override |
| | | protected String encodeOffline(final byte[] plaintextBytes) throws DirectoryException |
| | | { |
| | | return PBKDF2PasswordStorageScheme.encodeOffline(plaintextBytes); |
| | | } |
| | | } |
| | |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | | import org.opends.server.TestCaseUtils; |
| | | import org.opends.server.admin.server.AdminTestCaseUtils; |
| | | import org.opends.server.admin.std.meta.PKCS5S2PasswordStorageSchemeCfgDefn; |
| | | import org.opends.server.admin.std.server.PKCS5S2PasswordStorageSchemeCfg; |
| | | import org.opends.server.api.PasswordStorageScheme; |
| | | import org.opends.server.types.Entry; |
| | | import org.opends.server.types.DirectoryException; |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import static org.testng.Assert.*; |
| | | |
| | | /** |
| | | * A set of test cases for the PKCS5S2 password storage scheme. |
| | | */ |
| | |
| | | String plaintextPassword, |
| | | String encodedPassword) throws Exception |
| | | { |
| | | // Start/clear-out the memory backend |
| | | TestCaseUtils.initializeTestBackend(true); |
| | | |
| | | boolean allowPreencodedDefault = setAllowPreencodedPasswords(true); |
| | | |
| | | try { |
| | | Entry userEntry = TestCaseUtils.makeEntry( |
| | | "dn: uid=testPKCS5S2.user,o=test", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: testPKCS5S2.user", |
| | | "givenName: TestPKCS5S2", |
| | | "sn: User", |
| | | "cn: TestPKCS5S2 User", |
| | | "userPassword: " + encodedPassword); |
| | | |
| | | TestCaseUtils.addEntry(userEntry); |
| | | |
| | | assertTrue(TestCaseUtils.canBind("uid=testPKCS5S2.user,o=test", plaintextPassword), |
| | | "Failed to bind when pre-encoded password = \"" + |
| | | encodedPassword + "\" and " + |
| | | "plaintext password = \"" + |
| | | plaintextPassword + "\"" ); |
| | | } finally { |
| | | setAllowPreencodedPasswords(allowPreencodedDefault); |
| | | testAuthPasswords("TestPKCS5S2", plaintextPassword, encodedPassword); |
| | | } |
| | | |
| | | @Override |
| | | protected String encodeOffline(final byte[] plaintextBytes) throws DirectoryException |
| | | { |
| | | return PKCS5S2PasswordStorageScheme.encodeOffline(plaintextBytes); |
| | | } |
| | | |
| | | } |
| | |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | | |
| | | |
| | | import static org.testng.Assert.*; |
| | | |
| | | import java.util.ArrayList; |
| | | |
| | | import org.opends.server.TestCaseUtils; |
| | |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import static org.testng.Assert.*; |
| | | |
| | | /** |
| | | * A set of generic test cases for password storage schemes. |
| | | */ |
| | | @SuppressWarnings("javadoc") |
| | | public abstract class PasswordStorageSchemeTestCase |
| | | extends ExtensionsTestCase |
| | | { |
| | | // The configuration entry for this password storage scheme. |
| | | /** The configuration entry for this password storage scheme. */ |
| | | protected ConfigEntry configEntry; |
| | | |
| | | // The string representation of the DN of the configuration entry for this |
| | | // password storage scheme. |
| | | /** |
| | | * The string representation of the DN of the configuration entry for this |
| | | * password storage scheme. |
| | | */ |
| | | private String configDNString; |
| | | |
| | | |
| | |
| | | * Ensures that the Directory Server is started before running any of these |
| | | * tests. |
| | | */ |
| | | @BeforeClass() |
| | | public void startServer() |
| | | throws Exception |
| | | @BeforeClass |
| | | public void startServer() throws Exception |
| | | { |
| | | TestCaseUtils.startServer(); |
| | | |
| | |
| | | @DataProvider(name = "testPasswords") |
| | | public Object[][] getTestPasswords() |
| | | { |
| | | return getTestPasswordsStatic(); |
| | | } |
| | | |
| | | static Object[][] getTestPasswordsStatic() |
| | | { |
| | | return new Object[][] |
| | | { |
| | | new Object[] { ByteString.empty() }, |
| | |
| | | * provided password, and ensures that the encoded value is correct. |
| | | * |
| | | * @param plaintext The plain-text version of the password to encode. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test(dataProvider = "testPasswords") |
| | | public void testStorageScheme(ByteString plaintext) |
| | | throws Exception |
| | | { |
| | | PasswordStorageScheme scheme = getScheme(); |
| | | testStorageScheme(plaintext, getScheme()); |
| | | } |
| | | |
| | | static void testStorageScheme(ByteString plaintext, |
| | | PasswordStorageScheme<?> scheme) throws Exception |
| | | { |
| | | assertNotNull(scheme); |
| | | assertNotNull(scheme.getStorageSchemeName()); |
| | | |
| | |
| | | |
| | | |
| | | @DataProvider |
| | | public Object[][] passwordsForBinding() |
| | | public static Object[][] passwordsForBinding() |
| | | { |
| | | return new Object[][] |
| | | { |
| | |
| | | @Test(dataProvider = "passwordsForBinding") |
| | | public void testSettingEncodedPassword(ByteString plainPassword) throws Exception |
| | | { |
| | | testSettingEncodedPassword(plainPassword, getScheme()); |
| | | } |
| | | |
| | | static void testSettingEncodedPassword(ByteString plainPassword, |
| | | PasswordStorageScheme<?> scheme) throws Exception, DirectoryException |
| | | { |
| | | // Start/clear-out the memory backend |
| | | TestCaseUtils.initializeTestBackend(true); |
| | | |
| | | boolean allowPreencodedDefault = setAllowPreencodedPasswords(true); |
| | | |
| | | try { |
| | | PasswordStorageScheme scheme = getScheme(); |
| | | ByteString schemeEncodedPassword = |
| | | scheme.encodePasswordWithScheme(plainPassword); |
| | | |
| | | // |
| | | // This code creates a user with the encoded password, |
| | | // and then verifies that they can bind with the raw password. |
| | | // |
| | | |
| | | Entry userEntry = TestCaseUtils.makeEntry( |
| | | "dn: uid=test.user,o=test", |
| | | "objectClass: top", |
| | |
| | | "sn: User", |
| | | "cn: Test User", |
| | | "ds-privilege-name: bypass-acl", |
| | | "userPassword: " + schemeEncodedPassword.toString()); |
| | | "userPassword: " + schemeEncodedPassword); |
| | | |
| | | // Add the entry |
| | | TestCaseUtils.addEntry(userEntry); |
| | | |
| | | assertTrue(TestCaseUtils.canBind("uid=test.user,o=test", |
| | | plainPassword.toString()), |
| | | "Failed to bind when pre-encoded password = \"" + |
| | | schemeEncodedPassword.toString() + "\" and " + |
| | | schemeEncodedPassword + "\" and " + |
| | | "plaintext password = \"" + |
| | | plainPassword.toString() + "\""); |
| | | plainPassword + "\""); |
| | | } finally { |
| | | setAllowPreencodedPasswords(allowPreencodedDefault); |
| | | } |
| | |
| | | * @param allowPreencoded whether or not to allow pre-encoded passwords |
| | | * @return the previous value for the allow preencoded passwords |
| | | */ |
| | | protected boolean setAllowPreencodedPasswords(boolean allowPreencoded) |
| | | protected static boolean setAllowPreencodedPasswords(boolean allowPreencoded) |
| | | throws Exception |
| | | { |
| | | // This code was borrowed from |
| | |
| | | return previousValue; |
| | | } |
| | | |
| | | protected static void testAuthPasswords(final String upperName, |
| | | String plaintextPassword, String encodedPassword) throws Exception |
| | | { |
| | | // Start/clear-out the memory backend |
| | | TestCaseUtils.initializeTestBackend(true); |
| | | |
| | | boolean allowPreencodedDefault = setAllowPreencodedPasswords(true); |
| | | |
| | | try |
| | | { |
| | | final String lowerName = |
| | | Character.toLowerCase(upperName.charAt(0)) + upperName.substring(1); |
| | | |
| | | Entry userEntry = TestCaseUtils.makeEntry( |
| | | "dn: uid=" + lowerName + ".user,o=test", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: " + lowerName + ".user", |
| | | "givenName: " + upperName, |
| | | "sn: User", |
| | | "cn: " + upperName + " User", |
| | | "userPassword: " + encodedPassword); |
| | | |
| | | TestCaseUtils.addEntry(userEntry); |
| | | |
| | | assertTrue(TestCaseUtils.canBind( |
| | | "uid=" + lowerName + ".user,o=test", plaintextPassword), |
| | | "Failed to bind when pre-encoded password = \"" + encodedPassword |
| | | + "\" and " + "plaintext password = \"" + plaintextPassword + "\""); |
| | | } |
| | | finally |
| | | { |
| | | setAllowPreencodedPasswords(allowPreencodedDefault); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Tests the <CODE>encodeOffline</CODE> method. |
| | | * |
| | | * @param plaintext |
| | | * The plaintext password to use for the test. |
| | | * @throws Exception |
| | | * If an unexpected problem occurs. |
| | | */ |
| | | @Test(dataProvider = "testPasswords") |
| | | public void testEncodeOffline(ByteString plaintext) throws Exception |
| | | { |
| | | PasswordStorageScheme<?> scheme = getScheme(); |
| | | String passwordString = encodeOffline(plaintext.toByteArray()); |
| | | if (passwordString != null) |
| | | { |
| | | String[] pwComps = UserPasswordSyntax.decodeUserPassword(passwordString); |
| | | ByteString encodedPassword = ByteString.valueOf(pwComps[1]); |
| | | |
| | | assertTrue(scheme.passwordMatches(plaintext, encodedPassword)); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * Retrieves an initialized instance of this password storage scheme. |
| | | * |
| | | * @return An initialized instance of this password storage scheme. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | * @throws Exception |
| | | * If an unexpected problem occurs. |
| | | */ |
| | | protected abstract PasswordStorageScheme getScheme() |
| | | throws Exception; |
| | | protected abstract PasswordStorageScheme<?> getScheme() throws Exception; |
| | | |
| | | /** |
| | | * Encodes the provided plaintext password while offline. |
| | | * |
| | | * @param plaintextBytes |
| | | * The plaintext password in bytes to use for the test. |
| | | * @throws DirectoryException |
| | | * If an unexpected problem occurs. |
| | | */ |
| | | protected String encodeOffline(byte[] plaintextBytes) throws DirectoryException |
| | | { |
| | | return null; |
| | | } |
| | | } |
| | | |
| | |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | | |
| | | |
| | | import org.testng.annotations.Test; |
| | | |
| | | import org.opends.server.admin.server.AdminTestCaseUtils; |
| | | import org.opends.server.admin.std.meta.SaltedSHA1PasswordStorageSchemeCfgDefn; |
| | | import org.opends.server.admin.std.server.SaltedSHA1PasswordStorageSchemeCfg; |
| | | import org.opends.server.api.PasswordStorageScheme; |
| | | import org.opends.server.schema.UserPasswordSyntax; |
| | | import org.forgerock.opendj.ldap.ByteString; |
| | | |
| | | import static org.testng.Assert.*; |
| | | |
| | | |
| | | import org.opends.server.types.DirectoryException; |
| | | |
| | | /** |
| | | * A set of test cases for the salted SHA-1 password storage scheme. |
| | |
| | | * Retrieves an initialized instance of this password storage scheme. |
| | | * |
| | | * @return An initialized instance of this password storage scheme. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | protected PasswordStorageScheme getScheme() |
| | | throws Exception |
| | | @Override |
| | | protected PasswordStorageScheme<?> getScheme() throws Exception |
| | | { |
| | | SaltedSHA1PasswordStorageScheme scheme = |
| | | new SaltedSHA1PasswordStorageScheme(); |
| | |
| | | return scheme; |
| | | } |
| | | |
| | | |
| | | |
| | | /** |
| | | * Tests the <CODE>encodeOffline</CODE> method. |
| | | * |
| | | * @param plaintext The plaintext password to use for the test. |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | @Test(dataProvider = "testPasswords") |
| | | public void testEncodeOffline(ByteString plaintext) |
| | | throws Exception |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | protected String encodeOffline(final byte[] plaintextBytes) throws DirectoryException |
| | | { |
| | | SaltedSHA1PasswordStorageScheme scheme = |
| | | new SaltedSHA1PasswordStorageScheme(); |
| | | |
| | | SaltedSHA1PasswordStorageSchemeCfg configuration = |
| | | AdminTestCaseUtils.getConfiguration( |
| | | SaltedSHA1PasswordStorageSchemeCfgDefn.getInstance(), |
| | | configEntry.getEntry() |
| | | ); |
| | | |
| | | scheme.initializePasswordStorageScheme(configuration); |
| | | |
| | | String passwordString = SaltedSHA1PasswordStorageScheme.encodeOffline(plaintext.toByteArray()); |
| | | String[] pwComps = UserPasswordSyntax.decodeUserPassword(passwordString); |
| | | ByteString encodedPassword = ByteString.valueOf(pwComps[1]); |
| | | |
| | | assertTrue(scheme.passwordMatches(plaintext, encodedPassword)); |
| | | return SaltedSHA1PasswordStorageScheme.encodeOffline(plaintextBytes); |
| | | } |
| | | } |
| | | |
| | |
| | | * |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2010 ForgeRock AS. |
| | | * Portions Copyright 2010-2014 ForgeRock AS. |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | | |
| | | import static org.testng.Assert.*; |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import org.opends.server.TestCaseUtils; |
| | | import org.opends.server.admin.server.AdminTestCaseUtils; |
| | | import org.opends.server.admin.std.meta. |
| | | SaltedSHA256PasswordStorageSchemeCfgDefn; |
| | | import org.opends.server.admin.std.meta.SaltedSHA256PasswordStorageSchemeCfgDefn; |
| | | import org.opends.server.admin.std.server.SaltedSHA256PasswordStorageSchemeCfg; |
| | | import org.opends.server.api.PasswordStorageScheme; |
| | | import org.opends.server.types.Entry; |
| | | |
| | | |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | |
| | | /** |
| | | * A set of test cases for the salted SHA-256 password storage scheme. |
| | | */ |
| | | @SuppressWarnings("javadoc") |
| | | public class SaltedSHA256PasswordStorageSchemeTestCase |
| | | extends PasswordStorageSchemeTestCase |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | protected PasswordStorageScheme getScheme() |
| | | throws Exception |
| | | @Override |
| | | protected PasswordStorageScheme<?> getScheme() throws Exception |
| | | { |
| | | SaltedSHA256PasswordStorageScheme scheme = |
| | | new SaltedSHA256PasswordStorageScheme(); |
| | |
| | | * @return A set of couple (cleartext, encrypted) passwords that |
| | | * may be used to test the SSHA256 password storage scheme |
| | | */ |
| | | |
| | | @DataProvider(name = "testSSHA256Passwords") |
| | | public Object[][] getTestSSHA256Passwords() |
| | | throws Exception |
| | | public Object[][] getTestSSHA256Passwords() throws Exception |
| | | { |
| | | return new Object[][] |
| | | { |
| | |
| | | String plaintextPassword, |
| | | String encodedPassword) throws Exception |
| | | { |
| | | // Start/clear-out the memory backend |
| | | TestCaseUtils.initializeTestBackend(true); |
| | | |
| | | boolean allowPreencodedDefault = setAllowPreencodedPasswords(true); |
| | | |
| | | try { |
| | | |
| | | Entry userEntry = TestCaseUtils.makeEntry( |
| | | "dn: uid=testSSHA256.user,o=test", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: testSSHA256.user", |
| | | "givenName: TestSSHA256", |
| | | "sn: User", |
| | | "cn: TestSSHA256 User", |
| | | "userPassword: " + encodedPassword); |
| | | |
| | | |
| | | // Add the entry |
| | | TestCaseUtils.addEntry(userEntry); |
| | | |
| | | assertTrue(TestCaseUtils.canBind("uid=testSSHA256.user,o=test", |
| | | plaintextPassword), |
| | | "Failed to bind when pre-encoded password = \"" + |
| | | encodedPassword + "\" and " + |
| | | "plaintext password = \"" + |
| | | plaintextPassword + "\"" ); |
| | | } finally { |
| | | setAllowPreencodedPasswords(allowPreencodedDefault); |
| | | } |
| | | testAuthPasswords("TestSSHA256", plaintextPassword, encodedPassword); |
| | | } |
| | | |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2010 ForgeRock AS. |
| | | * Portions Copyright 2010-2014 ForgeRock AS. |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | | |
| | | import static org.testng.Assert.*; |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import org.opends.server.TestCaseUtils; |
| | | |
| | | import org.opends.server.admin.server.AdminTestCaseUtils; |
| | | import org.opends.server.admin.std.meta. |
| | | SaltedSHA384PasswordStorageSchemeCfgDefn; |
| | | import org.opends.server.admin.std.meta.SaltedSHA384PasswordStorageSchemeCfgDefn; |
| | | import org.opends.server.admin.std.server.SaltedSHA384PasswordStorageSchemeCfg; |
| | | import org.opends.server.api.PasswordStorageScheme; |
| | | import org.opends.server.types.Entry; |
| | | |
| | | |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | |
| | | /** |
| | | * A set of test cases for the salted SHA-384 password storage scheme. |
| | | */ |
| | | @SuppressWarnings("javadoc") |
| | | public class SaltedSHA384PasswordStorageSchemeTestCase |
| | | extends PasswordStorageSchemeTestCase |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | protected PasswordStorageScheme getScheme() |
| | | throws Exception |
| | | @Override |
| | | protected PasswordStorageScheme<?> getScheme() throws Exception |
| | | { |
| | | SaltedSHA384PasswordStorageScheme scheme = |
| | | new SaltedSHA384PasswordStorageScheme(); |
| | |
| | | * @return A set of couple (cleartext, encrypted) passwords that |
| | | * may be used to test the SSHA384 password storage scheme |
| | | */ |
| | | |
| | | @DataProvider(name = "testSSHA384Passwords") |
| | | public Object[][] getTestSSHA384Passwords() |
| | | throws Exception |
| | | public Object[][] getTestSSHA384Passwords() throws Exception |
| | | { |
| | | return new Object[][] |
| | | { |
| | |
| | | String plaintextPassword, |
| | | String encodedPassword) throws Exception |
| | | { |
| | | // Start/clear-out the memory backend |
| | | TestCaseUtils.initializeTestBackend(true); |
| | | |
| | | boolean allowPreencodedDefault = setAllowPreencodedPasswords(true); |
| | | |
| | | try { |
| | | |
| | | Entry userEntry = TestCaseUtils.makeEntry( |
| | | "dn: uid=testSSHA384.user,o=test", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: testSSHA384.user", |
| | | "givenName: TestSSHA384", |
| | | "sn: User", |
| | | "cn: TestSSHA384 User", |
| | | "userPassword: " + encodedPassword); |
| | | |
| | | |
| | | // Add the entry |
| | | TestCaseUtils.addEntry(userEntry); |
| | | |
| | | assertTrue(TestCaseUtils.canBind("uid=testSSHA384.user,o=test", |
| | | plaintextPassword), |
| | | "Failed to bind when pre-encoded password = \"" + |
| | | encodedPassword + "\" and " + |
| | | "plaintext password = \"" + |
| | | plaintextPassword + "\"" ); |
| | | } finally { |
| | | setAllowPreencodedPasswords(allowPreencodedDefault); |
| | | } |
| | | testAuthPasswords("TestSSHA384", plaintextPassword, encodedPassword); |
| | | } |
| | | |
| | | } |
| | |
| | | * |
| | | * |
| | | * Copyright 2006-2008 Sun Microsystems, Inc. |
| | | * Portions Copyright 2010 ForgeRock AS. |
| | | * Portions Copyright 2010-2014 ForgeRock AS. |
| | | */ |
| | | package org.opends.server.extensions; |
| | | |
| | | |
| | | import static org.testng.Assert.*; |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | |
| | | import org.opends.server.TestCaseUtils; |
| | | |
| | | import org.opends.server.admin.server.AdminTestCaseUtils; |
| | | import org.opends.server.admin.std.meta. |
| | | SaltedSHA512PasswordStorageSchemeCfgDefn; |
| | | import org.opends.server.admin.std.meta.SaltedSHA512PasswordStorageSchemeCfgDefn; |
| | | import org.opends.server.admin.std.server.SaltedSHA512PasswordStorageSchemeCfg; |
| | | import org.opends.server.api.PasswordStorageScheme; |
| | | import org.opends.server.types.Entry; |
| | | |
| | | |
| | | import org.opends.server.types.DirectoryException; |
| | | import org.testng.annotations.DataProvider; |
| | | import org.testng.annotations.Test; |
| | | |
| | | /** |
| | | * A set of test cases for the salted SHA-512 password storage scheme. |
| | | */ |
| | | @SuppressWarnings("javadoc") |
| | | public class SaltedSHA512PasswordStorageSchemeTestCase |
| | | extends PasswordStorageSchemeTestCase |
| | | { |
| | |
| | | * |
| | | * @throws Exception If an unexpected problem occurs. |
| | | */ |
| | | protected PasswordStorageScheme getScheme() |
| | | throws Exception |
| | | @Override |
| | | protected PasswordStorageScheme<?> getScheme() throws Exception |
| | | { |
| | | SaltedSHA512PasswordStorageScheme scheme = |
| | | new SaltedSHA512PasswordStorageScheme(); |
| | |
| | | String plaintextPassword, |
| | | String encodedPassword) throws Exception |
| | | { |
| | | // Start/clear-out the memory backend |
| | | TestCaseUtils.initializeTestBackend(true); |
| | | |
| | | boolean allowPreencodedDefault = setAllowPreencodedPasswords(true); |
| | | |
| | | try { |
| | | |
| | | Entry userEntry = TestCaseUtils.makeEntry( |
| | | "dn: uid=testSSHA512.user,o=test", |
| | | "objectClass: top", |
| | | "objectClass: person", |
| | | "objectClass: organizationalPerson", |
| | | "objectClass: inetOrgPerson", |
| | | "uid: testSSHA512.user", |
| | | "givenName: TestSSHA512", |
| | | "sn: User", |
| | | "cn: TestSSHA512 User", |
| | | "userPassword: " + encodedPassword); |
| | | |
| | | |
| | | // Add the entry |
| | | TestCaseUtils.addEntry(userEntry); |
| | | |
| | | assertTrue(TestCaseUtils.canBind("uid=testSSHA512.user,o=test", |
| | | plaintextPassword), |
| | | "Failed to bind when pre-encoded password = \"" + |
| | | encodedPassword + "\" and " + |
| | | "plaintext password = \"" + |
| | | plaintextPassword + "\"" ); |
| | | } finally { |
| | | setAllowPreencodedPasswords(allowPreencodedDefault); |
| | | } |
| | | testAuthPasswords("TestSSHA512", plaintextPassword, encodedPassword); |
| | | } |
| | | |
| | | /** {@inheritDoc} */ |
| | | @Override |
| | | protected String encodeOffline(byte[] plaintextBytes) throws DirectoryException |
| | | { |
| | | return SaltedSHA512PasswordStorageScheme.encodeOffline(plaintextBytes); |
| | | } |
| | | |
| | | } |