From 99d33a80f9ac8ee98c24e1bcce9deab8b9815bf2 Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Fri, 12 Sep 2014 14:15:15 +0000
Subject: [PATCH] Code cleanup for password storage schemes. Used AutoRefactor. Reduced variable scopes.
---
opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PBKDF2PasswordStorageSchemeTestCase.java | 87 +++++++
opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PKCS5S2PasswordStorageSchemeTestCase.java | 38 ++-
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/extensions/PBKDF2PasswordStorageScheme.java | 372 +++++++++---------------------
opendj-sdk/opendj3-server-dev/src/server/org/opends/server/extensions/PKCS5S2PasswordStorageScheme.java | 211 +++++------------
4 files changed, 294 insertions(+), 414 deletions(-)
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/extensions/PBKDF2PasswordStorageScheme.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/extensions/PBKDF2PasswordStorageScheme.java
index d2eab2e..a842995 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/extensions/PBKDF2PasswordStorageScheme.java
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/extensions/PBKDF2PasswordStorageScheme.java
@@ -21,35 +21,37 @@
* CDDL HEADER END
*
*
- * Portions Copyright 2013-2014 ForgeRock AS.
+ * Copyright 2013-2014 ForgeRock AS.
*/
package org.opends.server.extensions;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
+import java.security.spec.KeySpec;
import java.util.Arrays;
import java.util.List;
-import java.security.spec.KeySpec;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.i18n.slf4j.LocalizedLogger;
+import org.forgerock.opendj.config.server.ConfigException;
+import org.forgerock.opendj.ldap.ByteSequence;
+import org.forgerock.opendj.ldap.ByteString;
+import org.forgerock.opendj.ldap.ResultCode;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.server.PBKDF2PasswordStorageSchemeCfg;
import org.opends.server.api.PasswordStorageScheme;
-import org.forgerock.opendj.config.server.ConfigException;
import org.opends.server.core.DirectoryServer;
-import org.forgerock.i18n.slf4j.LocalizedLogger;
-import org.opends.server.types.*;
-import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.ByteString;
-import org.forgerock.opendj.ldap.ByteSequence;
+import org.opends.server.types.ConfigChangeResult;
+import org.opends.server.types.DirectoryException;
+import org.opends.server.types.InitializationException;
import org.opends.server.util.Base64;
import static org.opends.messages.ExtensionMessages.*;
import static org.opends.server.extensions.ExtensionsConstants.*;
-import static org.opends.server.util.StaticUtils.getExceptionMessage;
+import static org.opends.server.util.StaticUtils.*;
/**
* This class defines a Directory Server password storage scheme based on the
@@ -65,9 +67,7 @@
{
private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
- /**
- * The fully-qualified name of this class.
- */
+ /** The fully-qualified name of this class. */
private static final String CLASS_NAME =
"org.opends.server.extensions.PBKDF2PasswordStorageScheme";
@@ -78,19 +78,19 @@
*/
private static final int NUM_SALT_BYTES = 8;
- // The number of bytes the SHA-1 algorithm produces
+ /** The number of bytes the SHA-1 algorithm produces. */
private static final int SHA1_LENGTH = 20;
- // The factory used to generate the PBKDF2 hashes.
+ /** The factory used to generate the PBKDF2 hashes. */
private SecretKeyFactory factory;
- // The lock used to provide threadsafe access to the message digest.
- private Object factoryLock;
+ /** The lock used to provide thread-safe access to the message digest. */
+ private final Object factoryLock = new Object();
- // The secure random number generator to use to generate the salt values.
+ /** The secure random number generator to use to generate the salt values. */
private SecureRandom random;
- // The current configuration for this storage scheme.
+ /** The current configuration for this storage scheme. */
private volatile PBKDF2PasswordStorageSchemeCfg config;
@@ -104,17 +104,12 @@
super();
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public void initializePasswordStorageScheme(
PBKDF2PasswordStorageSchemeCfg configuration)
throws ConfigException, InitializationException
{
- factoryLock = new Object();
try
{
random = SecureRandom.getInstance(SECURE_PRNG_SHA1);
@@ -129,24 +124,17 @@
config.addPBKDF2ChangeListener(this);
}
-
-
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
+ @Override
public boolean isConfigurationChangeAcceptable(
PBKDF2PasswordStorageSchemeCfg configuration,
List<LocalizableMessage> unacceptableReasons)
{
- // The configuration will always be acceptable.
return true;
}
-
-
- /**
- * {@inheritDoc}
- */
+ /** {@inheritDoc} */
+ @Override
public ConfigChangeResult applyConfigurationChange(
PBKDF2PasswordStorageSchemeCfg configuration)
{
@@ -154,57 +142,22 @@
return new ConfigChangeResult(ResultCode.SUCCESS, false);
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public String getStorageSchemeName()
{
return STORAGE_SCHEME_NAME_PBKDF2;
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public ByteString encodePassword(ByteSequence plaintext)
throws DirectoryException
{
byte[] saltBytes = new byte[NUM_SALT_BYTES];
- byte[] digestBytes;
- char[] plaintextChars = null;
int iterations = config.getPBKDF2Iterations();
- synchronized(factoryLock)
- {
- try
- {
- random.nextBytes(saltBytes);
-
- plaintextChars = plaintext.toString().toCharArray();
- KeySpec spec = new PBEKeySpec(plaintextChars,
- saltBytes, iterations, SHA1_LENGTH * 8);
- digestBytes = 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');
- }
- }
+ 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];
@@ -212,73 +165,49 @@
System.arraycopy(saltBytes, 0, hashPlusSalt, digestBytes.length,
NUM_SALT_BYTES);
- StringBuilder sb = new StringBuilder();
- sb.append(Integer.toString(iterations));
- sb.append(':');
- sb.append(Base64.encode(hashPlusSalt));
- return ByteString.valueOf(sb.toString());
+ return ByteString.valueOf(iterations + ":" + Base64.encode(hashPlusSalt));
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public ByteString encodePasswordWithScheme(ByteSequence plaintext)
throws DirectoryException
{
- StringBuilder buffer = new StringBuilder();
- buffer.append('{');
- buffer.append(STORAGE_SCHEME_NAME_PBKDF2);
- buffer.append('}');
-
- buffer.append(encodePassword(plaintext));
-
- return ByteString.valueOf(buffer.toString());
+ return ByteString.valueOf('{' + STORAGE_SCHEME_NAME_PBKDF2 + '}'
+ + encodePassword(plaintext));
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public boolean passwordMatches(ByteSequence plaintextPassword,
ByteSequence storedPassword)
{
-
- // Split the iterations from the stored value (separated by a ":")
+ // Split the iterations from the stored value (separated by a ':')
// Base64-decode the remaining value and take the last 8 bytes as the salt.
- int iterations;
- byte[] saltBytes;
- byte[] digestBytes = new byte[SHA1_LENGTH];
- int saltLength = 0;
try
{
String stored = storedPassword.toString();
- int stored_length = stored.length();
- int pos = 0;
- while (pos < stored_length && stored.charAt(pos) != ':')
+ int pos = stored.indexOf(':');
+ if (pos == -1)
{
- pos++;
- }
- if (pos >= (stored_length - 1) || pos == 0)
throw new Exception();
+ }
- iterations = Integer.parseInt(stored.substring(0, pos));
+ final int iterations = Integer.parseInt(stored.substring(0, pos));
byte[] decodedBytes = Base64.decode(stored.substring(pos + 1));
- saltLength = decodedBytes.length - SHA1_LENGTH;
+ final int saltLength = decodedBytes.length - SHA1_LENGTH;
if (saltLength <= 0)
{
logger.error(ERR_PWSCHEME_INVALID_BASE64_DECODED_STORED_PASSWORD, storedPassword);
return false;
}
- saltBytes = new byte[saltLength];
+
+ final byte[] digestBytes = new byte[SHA1_LENGTH];
+ final byte[] saltBytes = new byte[saltLength];
System.arraycopy(decodedBytes, 0, digestBytes, 0, SHA1_LENGTH);
- System.arraycopy(decodedBytes, SHA1_LENGTH, saltBytes, 0,
- saltLength);
+ System.arraycopy(decodedBytes, SHA1_LENGTH, saltBytes, 0, saltLength);
+ return encodeAndMatch(plaintextPassword, saltBytes, digestBytes, iterations);
}
catch (Exception e)
{
@@ -286,18 +215,19 @@
logger.error(ERR_PWSCHEME_CANNOT_BASE64_DECODE_STORED_PASSWORD, storedPassword, e);
return false;
}
+ }
-
+ 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 + saltLength];
+ byte[] plainPlusSalt = new byte[plainBytesLength + saltBytes.length];
plaintextPassword.copyTo(plainPlusSalt);
- System.arraycopy(saltBytes, 0, plainPlusSalt, plainBytesLength,
- saltLength);
+ System.arraycopy(saltBytes, 0, plainPlusSalt, plainBytesLength, saltBytes.length);
- byte[] userDigestBytes;
+
char[] plaintextChars = null;
-
synchronized (factoryLock)
{
try
@@ -306,62 +236,58 @@
KeySpec spec = new PBEKeySpec(
plaintextChars, saltBytes,
iterations, SHA1_LENGTH * 8);
- userDigestBytes = factory.generateSecret(spec).getEncoded();
+ 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');
+ }
}
}
-
- return Arrays.equals(digestBytes, userDigestBytes);
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public boolean supportsAuthPasswordSyntax()
{
- // This storage scheme does support the authentication password syntax.
return true;
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public String getAuthPasswordSchemeName()
{
return AUTH_PASSWORD_SCHEME_NAME_PBKDF2;
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public ByteString encodeAuthPassword(ByteSequence plaintext)
throws DirectoryException
{
byte[] saltBytes = new byte[NUM_SALT_BYTES];
- byte[] digestBytes;
- char[] plaintextChars = null;
int iterations = config.getPBKDF2Iterations();
+ byte[] digestBytes = getDigestBytes(plaintext, saltBytes, iterations);
- synchronized(factoryLock)
+ // Encode and return the value.
+ return ByteString.valueOf(AUTH_PASSWORD_SCHEME_NAME_PBKDF2 + '$'
+ + iterations + ':' + Base64.encode(saltBytes) + '$'
+ + Base64.encode(digestBytes));
+ }
+
+ private byte[] getDigestBytes(ByteSequence plaintext, byte[] saltBytes,
+ int iterations) throws DirectoryException
+ {
+ char[] plaintextChars = null;
+ synchronized (factoryLock)
{
try
{
@@ -371,7 +297,7 @@
KeySpec spec = new PBEKeySpec(
plaintextChars, saltBytes,
iterations, SHA1_LENGTH * 8);
- digestBytes = factory.generateSecret(spec).getEncoded();
+ return factory.generateSecret(spec).getEncoded();
}
catch (Exception e)
{
@@ -385,109 +311,46 @@
finally
{
if (plaintextChars != null)
+ {
Arrays.fill(plaintextChars, '0');
+ }
}
}
- // Encode and return the value.
- StringBuilder authPWValue = new StringBuilder();
- authPWValue.append(AUTH_PASSWORD_SCHEME_NAME_PBKDF2);
- authPWValue.append('$');
- authPWValue.append(Integer.toString(iterations));
- authPWValue.append(':');
- authPWValue.append(Base64.encode(saltBytes));
- authPWValue.append('$');
- authPWValue.append(Base64.encode(digestBytes));
-
- return ByteString.valueOf(authPWValue.toString());
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public boolean authPasswordMatches(ByteSequence plaintextPassword,
String authInfo, String authValue)
{
- byte[] saltBytes;
- byte[] digestBytes;
- int iterations;
-
try
{
- int pos = 0;
- int length = authInfo.length();
- while (pos < length && authInfo.charAt(pos) != ':')
+ int pos = authInfo.indexOf(':');
+ if (pos == -1)
{
- pos++;
- }
- if (pos >= (length - 1) || pos == 0)
throw new Exception();
- iterations = Integer.parseInt(authInfo.substring(0, pos));
- saltBytes = Base64.decode(authInfo.substring(pos + 1));
- digestBytes = Base64.decode(authValue);
+ }
+ int iterations = Integer.parseInt(authInfo.substring(0, pos));
+ byte[] saltBytes = Base64.decode(authInfo.substring(pos + 1));
+ byte[] digestBytes = Base64.decode(authValue);
+ return encodeAndMatch(plaintextPassword, saltBytes, digestBytes, iterations);
}
catch (Exception e)
{
logger.traceException(e);
-
return false;
}
-
-
- int plainBytesLength = plaintextPassword.length();
- byte[] plainPlusSalt = new byte[plainBytesLength + saltBytes.length];
- plaintextPassword.copyTo(plainPlusSalt);
- System.arraycopy(saltBytes, 0, plainPlusSalt, plainBytesLength,
- saltBytes.length);
-
- byte[] userDigestBytes;
- char[] plaintextChars = null;
-
- synchronized (factoryLock)
- {
- try
- {
- plaintextChars = plaintextPassword.toString().toCharArray();
- KeySpec spec = new PBEKeySpec(
- plaintextChars, saltBytes,
- iterations, SHA1_LENGTH * 8);
- userDigestBytes = factory.generateSecret(spec).getEncoded();
- }
- catch (Exception e)
- {
- logger.traceException(e);
-
- return false;
- }
- finally
- {
- if (plaintextChars != null)
- Arrays.fill(plaintextChars, '0');
- }
- }
-
- return Arrays.equals(digestBytes, userDigestBytes);
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public boolean isReversible()
{
return false;
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public ByteString getPlaintextValue(ByteSequence storedPassword)
throws DirectoryException
{
@@ -496,12 +359,8 @@
throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public ByteString getAuthPasswordPlaintextValue(String authInfo,
String authValue)
throws DirectoryException
@@ -511,15 +370,10 @@
throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public boolean isStorageSchemeSecure()
{
- // PBKDF2 should be considered secure.
return true;
}
@@ -542,19 +396,33 @@
throws DirectoryException
{
byte[] saltBytes = new byte[NUM_SALT_BYTES];
- byte[] digestBytes;
- char[] plaintextChars = null;
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];
+
+ 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);
+ }
+
+ private static byte[] getDigestBytes(byte[] plaintext, byte[] saltBytes,
+ int iterations) throws DirectoryException
+ {
+ char[] plaintextChars = null;
try
{
SecureRandom.getInstance(SECURE_PRNG_SHA1).nextBytes(saltBytes);
- plaintextChars = passwordBytes.toString().toCharArray();
+ plaintextChars = plaintext.toString().toCharArray();
KeySpec spec = new PBEKeySpec(
plaintextChars, saltBytes,
iterations, SHA1_LENGTH * 8);
- digestBytes = SecretKeyFactory
+ return SecretKeyFactory
.getInstance(MESSAGE_DIGEST_ALGORITHM_PBKDF2)
.generateSecret(spec).getEncoded();
}
@@ -570,18 +438,10 @@
finally
{
if (plaintextChars != null)
+ {
Arrays.fill(plaintextChars, '0');
+ }
}
-
- // 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);
-
- return "{" + STORAGE_SCHEME_NAME_PBKDF2 + "}" + iterations + ":" +
- Base64.encode(hashPlusSalt);
}
}
diff --git a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/extensions/PKCS5S2PasswordStorageScheme.java b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/extensions/PKCS5S2PasswordStorageScheme.java
index a99de0c..014324f 100644
--- a/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/extensions/PKCS5S2PasswordStorageScheme.java
+++ b/opendj-sdk/opendj3-server-dev/src/server/org/opends/server/extensions/PKCS5S2PasswordStorageScheme.java
@@ -26,6 +26,14 @@
*/
package org.opends.server.extensions;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.security.spec.KeySpec;
+import java.util.Arrays;
+
+import javax.crypto.SecretKeyFactory;
+import javax.crypto.spec.PBEKeySpec;
+
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.ldap.ByteSequence;
@@ -38,16 +46,9 @@
import org.opends.server.types.InitializationException;
import org.opends.server.util.Base64;
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.spec.PBEKeySpec;
-import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.security.spec.KeySpec;
-import java.util.Arrays;
-
import static org.opends.messages.ExtensionMessages.*;
import static org.opends.server.extensions.ExtensionsConstants.*;
-import static org.opends.server.util.StaticUtils.getExceptionMessage;
+import static org.opends.server.util.StaticUtils.*;
/**
* This class defines a Directory Server password storage scheme based on the
@@ -63,9 +64,7 @@
{
private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
- /**
- * The fully-qualified name of this class.
- */
+ /** The fully-qualified name of this class. */
private static final String CLASS_NAME =
"org.opends.server.extensions.PKCS5S2PasswordStorageScheme";
@@ -76,29 +75,19 @@
*/
private static final int NUM_SALT_BYTES = 16;
- /**
- * The number of bytes the SHA-1 algorithm produces.
- */
+ /** The number of bytes the SHA-1 algorithm produces. */
private static final int SHA1_LENGTH = 32;
- /**
- * Atlassian hardcoded the number of iterations to 10000.
- */
+ /** Atlassian hardcoded the number of iterations to 10000. */
private static final int iterations = 10000;
- /**
- * The factory used to generate the PKCS5S2 hashes.
- */
+ /** The factory used to generate the PKCS5S2 hashes. */
private SecretKeyFactory factory;
- /**
- * The lock used to provide thread-safe access to the message digest.
- */
+ /** The lock used to provide thread-safe access to the message digest. */
private final Object factoryLock = new Object();
- /**
- * The secure random number generator to use to generate the salt values.
- */
+ /** The secure random number generator to use to generate the salt values. */
private SecureRandom random;
@@ -112,12 +101,8 @@
super();
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public void initializePasswordStorageScheme(
PKCS5S2PasswordStorageSchemeCfg configuration)
throws InitializationException
@@ -133,21 +118,15 @@
}
}
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public String getStorageSchemeName()
{
return STORAGE_SCHEME_NAME_PKCS5S2;
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public ByteString encodePassword(ByteSequence plaintext)
throws DirectoryException
{
@@ -159,32 +138,21 @@
return ByteString.valueOf(Base64.encode(hashPlusSalt));
}
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public ByteString encodePasswordWithScheme(ByteSequence plaintext)
throws DirectoryException
{
- return ByteString.valueOf("{" + STORAGE_SCHEME_NAME_PKCS5S2 + '}'
+ return ByteString.valueOf('{' + STORAGE_SCHEME_NAME_PKCS5S2 + '}'
+ encodePassword(plaintext));
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public boolean passwordMatches(ByteSequence plaintextPassword,
ByteSequence storedPassword)
{
-
// Base64-decode the value and take the first 16 bytes as the salt.
- byte[] saltBytes = new byte[NUM_SALT_BYTES];
- final int saltLength = NUM_SALT_BYTES;
- byte[] digestBytes = new byte[SHA1_LENGTH];
try
{
String stored = storedPassword.toString();
@@ -197,9 +165,13 @@
storedPassword.toString()));
return false;
}
+
+ final int saltLength = NUM_SALT_BYTES;
+ byte[] saltBytes = new byte[saltLength];
+ byte[] digestBytes = new byte[SHA1_LENGTH];
System.arraycopy(decodedBytes, 0, saltBytes, 0, saltLength);
- System.arraycopy(decodedBytes, saltLength, digestBytes, 0,
- SHA1_LENGTH);
+ System.arraycopy(decodedBytes, saltLength, digestBytes, 0, SHA1_LENGTH);
+ return encodeAndMatch(plaintextPassword, saltBytes, digestBytes, iterations);
}
catch (Exception e)
{
@@ -208,102 +180,68 @@
storedPassword.toString(), String.valueOf(e)));
return false;
}
-
- return encodeAndMatch(plaintextPassword, saltBytes, digestBytes, iterations);
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public boolean supportsAuthPasswordSyntax()
{
return true;
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public String getAuthPasswordSchemeName()
{
return AUTH_PASSWORD_SCHEME_NAME_PKCS5S2;
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public ByteString encodeAuthPassword(ByteSequence plaintext)
throws DirectoryException
{
byte[] saltBytes = new byte[NUM_SALT_BYTES];
byte[] digestBytes = createRandomSaltAndEncode(plaintext, saltBytes);
// Encode and return the value.
- return ByteString.valueOf(AUTH_PASSWORD_SCHEME_NAME_PKCS5S2 + '$' +
- iterations + ':' + Base64.encode(saltBytes) +
- '$' + Base64.encode(digestBytes));
+ return ByteString.valueOf(AUTH_PASSWORD_SCHEME_NAME_PKCS5S2 + '$'
+ + iterations + ':' + Base64.encode(saltBytes) + '$'
+ + Base64.encode(digestBytes));
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public boolean authPasswordMatches(ByteSequence plaintextPassword,
String authInfo, String authValue)
{
- byte[] saltBytes;
- byte[] digestBytes;
- int iterations;
-
try
{
- int pos = 0;
- int length = authInfo.length();
- while (pos < length && authInfo.charAt(pos) != ':')
+ int pos = authInfo.indexOf(':');
+ if (pos == -1)
{
- pos++;
+ return false;
}
- if (pos >= (length - 1) || pos == 0)
- throw new Exception();
- iterations = Integer.parseInt(authInfo.substring(0, pos));
- saltBytes = Base64.decode(authInfo.substring(pos + 1));
- digestBytes = Base64.decode(authValue);
+ int iterations = Integer.parseInt(authInfo.substring(0, pos));
+ byte[] saltBytes = Base64.decode(authInfo.substring(pos + 1));
+ byte[] digestBytes = Base64.decode(authValue);
+ return encodeAndMatch(plaintextPassword, saltBytes, digestBytes, iterations);
}
catch (Exception e)
{
- logger.traceException(e);
- return false;
+ logger.traceException(e);
+ return false;
}
-
- return encodeAndMatch(plaintextPassword, saltBytes, digestBytes, iterations);
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public boolean isReversible()
{
return false;
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public ByteString getPlaintextValue(ByteSequence storedPassword)
throws DirectoryException
{
@@ -312,12 +250,8 @@
throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public ByteString getAuthPasswordPlaintextValue(String authInfo,
String authValue)
throws DirectoryException
@@ -327,12 +261,8 @@
throw new DirectoryException(ResultCode.CONSTRAINT_VIOLATION, message);
}
-
-
- /**
- * {@inheritDoc}
- */
- @Override()
+ /** {@inheritDoc} */
+ @Override
public boolean isStorageSchemeSecure()
{
return true;
@@ -351,7 +281,7 @@
* @return The encoded password string, including the scheme name in curly
* braces.
*
- * @throws org.opends.server.types.DirectoryException If a problem occurs during processing.
+ * @throws DirectoryException If a problem occurs during processing.
*/
public static String encodeOffline(byte[] passwordBytes)
throws DirectoryException
@@ -382,7 +312,7 @@
// Append the hashed value to the salt and base64-the whole thing.
byte[] hashPlusSalt = concatenateSaltPlusHash(saltBytes, digestBytes);
- return "{" + STORAGE_SCHEME_NAME_PKCS5S2 + "}" +
+ return '{' + STORAGE_SCHEME_NAME_PKCS5S2 + '}' +
Base64.encode(hashPlusSalt);
}
@@ -390,33 +320,27 @@
private boolean encodeAndMatch(ByteSequence plaintext,
byte[] saltBytes, byte[] digestBytes, int iterations)
{
- byte[] userDigestBytes;
-
try
{
- userDigestBytes = encodeWithSalt(plaintext, saltBytes, iterations);
+ byte[] userDigestBytes = encodeWithSalt(plaintext, saltBytes, iterations);
+ return Arrays.equals(digestBytes, userDigestBytes);
}
catch (Exception e)
{
- return false;
+ return false;
}
- return Arrays.equals(digestBytes, userDigestBytes);
}
private byte[] createRandomSaltAndEncode(ByteSequence plaintext, byte[] saltBytes) throws DirectoryException {
- byte[] digestBytes;
-
synchronized(factoryLock)
{
random.nextBytes(saltBytes);
- digestBytes = encodeWithSalt(plaintext, saltBytes, iterations);
+ return encodeWithSalt(plaintext, saltBytes, iterations);
}
- return digestBytes;
}
private byte[] encodeWithSalt(ByteSequence plaintext, byte[] saltBytes, int iterations) throws DirectoryException {
- byte[] digestBytes;
char[] plaintextChars = null;
try
{
@@ -424,7 +348,7 @@
KeySpec spec = new PBEKeySpec(
plaintextChars, saltBytes,
iterations, SHA1_LENGTH * 8);
- digestBytes = factory.generateSecret(spec).getEncoded();
+ return factory.generateSecret(spec).getEncoded();
}
catch (Exception e)
{
@@ -442,7 +366,6 @@
Arrays.fill(plaintextChars, '0');
}
}
- return digestBytes;
}
private static byte[] concatenateSaltPlusHash(byte[] saltBytes, byte[] digestBytes) {
diff --git a/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PBKDF2PasswordStorageSchemeTestCase.java b/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PBKDF2PasswordStorageSchemeTestCase.java
new file mode 100644
index 0000000..6bf6828
--- /dev/null
+++ b/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PBKDF2PasswordStorageSchemeTestCase.java
@@ -0,0 +1,87 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2014 ForgeRock AS.
+ */
+package org.opends.server.extensions;
+
+import org.opends.server.admin.server.AdminTestCaseUtils;
+import org.opends.server.admin.std.meta.PBKDF2PasswordStorageSchemeCfgDefn;
+import org.opends.server.admin.std.server.PBKDF2PasswordStorageSchemeCfg;
+import org.opends.server.api.PasswordStorageScheme;
+import org.testng.annotations.DataProvider;
+
+/**
+ * A set of test cases for the PBKDF2 password storage scheme.
+ */
+public class PBKDF2PasswordStorageSchemeTestCase
+ extends PasswordStorageSchemeTestCase
+{
+ /** Creates a new instance of this storage scheme test case. */
+ public PBKDF2PasswordStorageSchemeTestCase()
+ {
+ super("cn=PBKDF2,cn=Password Storage Schemes,cn=config");
+ }
+
+ /**
+ * Retrieves a set of passwords that may be used to test the password storage scheme.
+ *
+ * @return A set of passwords that may be used to test the password storage scheme.
+ */
+ @Override
+ @DataProvider(name = "testPasswords")
+ public Object[][] getTestPasswords()
+ {
+ final Object[][] testPasswords = super.getTestPasswords();
+
+ // JDK Bug 6879540. Empty passwords are not accepted when generating PBESpecKey.
+ // The bug is present in Java 6 and some version of Java 7.
+ final int newLength = testPasswords.length - 2;
+ final Object[][] results = new Object[newLength][];
+ System.arraycopy(testPasswords, 2, results, 0, newLength);
+ return results;
+ }
+
+
+ /**
+ * Retrieves an initialized instance of this password storage scheme.
+ *
+ * @return An initialized instance of this password storage scheme.
+ */
+ @Override
+ protected PasswordStorageScheme<?> getScheme() throws Exception
+ {
+ PBKDF2PasswordStorageScheme scheme =
+ new PBKDF2PasswordStorageScheme();
+
+ PBKDF2PasswordStorageSchemeCfg configuration =
+ AdminTestCaseUtils.getConfiguration(
+ PBKDF2PasswordStorageSchemeCfgDefn.getInstance(),
+ configEntry.getEntry()
+ );
+
+ scheme.initializePasswordStorageScheme(configuration);
+ return scheme;
+ }
+
+}
diff --git a/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PKCS5S2PasswordStorageSchemeTestCase.java b/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PKCS5S2PasswordStorageSchemeTestCase.java
index dfac4e3..6df2e8f 100644
--- a/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PKCS5S2PasswordStorageSchemeTestCase.java
+++ b/opendj-sdk/opendj3-server-dev/tests/unit-tests-testng/src/server/org/opends/server/extensions/PKCS5S2PasswordStorageSchemeTestCase.java
@@ -25,7 +25,6 @@
*/
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;
@@ -35,12 +34,12 @@
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
-import static org.testng.Assert.assertTrue;
-
+import static org.testng.Assert.*;
/**
* A set of test cases for the PKCS5S2 password storage scheme.
*/
+@SuppressWarnings("javadoc")
public class PKCS5S2PasswordStorageSchemeTestCase
extends PasswordStorageSchemeTestCase
{
@@ -52,17 +51,33 @@
super("cn=PKCS5S2,cn=Password Storage Schemes,cn=config");
}
+ /**
+ * Retrieves a set of passwords that may be used to test the password storage scheme.
+ *
+ * @return A set of passwords that may be used to test the password storage scheme.
+ */
+ @Override
+ @DataProvider(name = "testPasswords")
+ public Object[][] getTestPasswords()
+ {
+ final Object[][] testPasswords = super.getTestPasswords();
+
+ // JDK Bug 6879540. Empty passwords are not accepted when generating PBESpecKey.
+ // The bug is present in Java 6 and some version of Java 7.
+ final int newLength = testPasswords.length - 2;
+ final Object[][] results = new Object[newLength][];
+ System.arraycopy(testPasswords, 2, results, 0, newLength);
+ return results;
+ }
/**
* 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
{
PKCS5S2PasswordStorageScheme scheme =
new PKCS5S2PasswordStorageScheme();
@@ -86,10 +101,8 @@
* @return A set of couple (cleartext, encrypted) passwords that
* may be used to test the PKCS5S2 password storage scheme
*/
-
@DataProvider(name = "testPKCS5S2Passwords")
- public Object[][] getTestPKCS5S2Passwords()
- throws Exception
+ public Object[][] getTestPKCS5S2Passwords() throws Exception
{
return new Object[][]
{
@@ -131,7 +144,6 @@
boolean allowPreencodedDefault = setAllowPreencodedPasswords(true);
try {
-
Entry userEntry = TestCaseUtils.makeEntry(
"dn: uid=testPKCS5S2.user,o=test",
"objectClass: top",
@@ -146,8 +158,7 @@
TestCaseUtils.addEntry(userEntry);
- assertTrue(TestCaseUtils.canBind("uid=testPKCS5S2.user,o=test",
- plaintextPassword),
+ assertTrue(TestCaseUtils.canBind("uid=testPKCS5S2.user,o=test", plaintextPassword),
"Failed to bind when pre-encoded password = \"" +
encodedPassword + "\" and " +
"plaintext password = \"" +
@@ -158,4 +169,3 @@
}
}
-
--
Gitblit v1.10.0