You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by an...@apache.org on 2013/09/04 11:51:37 UTC
svn commit: r1519962 - in /jackrabbit/oak/trunk/oak-core/src:
main/java/org/apache/jackrabbit/oak/spi/security/user/util/
test/java/org/apache/jackrabbit/oak/security/user/
test/java/org/apache/jackrabbit/oak/spi/security/user/util/
Author: angela
Date: Wed Sep 4 09:51:36 2013
New Revision: 1519962
URL: http://svn.apache.org/r1519962
Log:
OAK-50: user mgt
PasswordUtil:
- revert internal methods being made public for test cases
- add annotations
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/util/PasswordUtil.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserManagerImplTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/util/PasswordUtilTest.java
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/util/PasswordUtil.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/util/PasswordUtil.java?rev=1519962&r1=1519961&r2=1519962&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/util/PasswordUtil.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/util/PasswordUtil.java Wed Sep 4 09:51:36 2013
@@ -23,7 +23,8 @@ import java.security.NoSuchAlgorithmExce
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
-
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
@@ -34,6 +35,8 @@ import org.apache.jackrabbit.util.Text;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static com.google.common.base.Preconditions.checkNotNull;
+
/**
* Utility to generate and compare password hashes.
*/
@@ -68,7 +71,7 @@ public final class PasswordUtil {
* @throws NoSuchAlgorithmException If {@link #DEFAULT_ALGORITHM} is not supported.
* @throws UnsupportedEncodingException If utf-8 is not supported.
*/
- public static String buildPasswordHash(String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {
+ public static String buildPasswordHash(@Nonnull String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {
return buildPasswordHash(password, DEFAULT_ALGORITHM, DEFAULT_SALT_SIZE, DEFAULT_ITERATIONS);
}
@@ -77,7 +80,8 @@ public final class PasswordUtil {
* salt size and number of iterations into account.
*
* @param password The password to be hashed.
- * @param algorithm The desired hash algorithm.
+ * @param algorithm The desired hash algorithm. If the algorith is
+ * {@code null} the {@link #DEFAULT_ALGORITHM} will be used.
* @param saltSize The desired salt size. If the specified integer is lower
* that {@link #DEFAULT_SALT_SIZE} the default is used.
* @param iterations The desired number of iterations. If the specified
@@ -86,11 +90,10 @@ public final class PasswordUtil {
* @throws NoSuchAlgorithmException If the specified algorithm is not supported.
* @throws UnsupportedEncodingException If utf-8 is not supported.
*/
- public static String buildPasswordHash(String password, String algorithm,
+ public static String buildPasswordHash(@Nonnull String password,
+ @Nullable String algorithm,
int saltSize, int iterations) throws NoSuchAlgorithmException, UnsupportedEncodingException {
- if (password == null) {
- throw new IllegalArgumentException("Password may not be null.");
- }
+ checkNotNull(password);
if (iterations < NO_ITERATIONS) {
iterations = DEFAULT_ITERATIONS;
}
@@ -112,10 +115,9 @@ public final class PasswordUtil {
* @throws NoSuchAlgorithmException If the specified algorithm is not supported.
* @throws UnsupportedEncodingException If utf-8 is not supported.
*/
- public static String buildPasswordHash(String password, ConfigurationParameters config) throws NoSuchAlgorithmException, UnsupportedEncodingException {
- if (config == null) {
- throw new IllegalArgumentException("UserConfig must not be null");
- }
+ public static String buildPasswordHash(@Nonnull String password,
+ @Nonnull ConfigurationParameters config) throws NoSuchAlgorithmException, UnsupportedEncodingException {
+ checkNotNull(config);
String algorithm = config.getConfigValue(UserConstants.PARAM_PASSWORD_HASH_ALGORITHM, DEFAULT_ALGORITHM);
int iterations = config.getConfigValue(UserConstants.PARAM_PASSWORD_HASH_ITERATIONS, DEFAULT_ITERATIONS);
int saltSize = config.getConfigValue(UserConstants.PARAM_PASSWORD_SALT_SIZE, DEFAULT_SALT_SIZE);
@@ -144,7 +146,7 @@ public final class PasswordUtil {
* @return If the hash created from the specified {@code password} equals
* the given {@code hashedPassword} string.
*/
- public static boolean isSame(String hashedPassword, char[] password) {
+ public static boolean isSame(@Nullable String hashedPassword, @Nonnull char[] password) {
return isSame(hashedPassword, String.valueOf(password));
}
@@ -157,7 +159,10 @@ public final class PasswordUtil {
* @return If the hash created from the specified {@code password} equals
* the given {@code hashedPassword} string.
*/
- public static boolean isSame(String hashedPassword, String password) {
+ public static boolean isSame(@Nullable String hashedPassword, @Nonnull String password) {
+ if (hashedPassword == null) {
+ return false;
+ }
try {
String algorithm = extractAlgorithm(hashedPassword);
if (algorithm != null) {
@@ -182,7 +187,8 @@ public final class PasswordUtil {
//------------------------------------------------------------< private >---
- public static String generateHash(String pwd, String algorithm, String salt, int iterations) throws NoSuchAlgorithmException, UnsupportedEncodingException {
+ private static String generateHash(@Nonnull String pwd, @Nonnull String algorithm,
+ @Nullable String salt, int iterations) throws NoSuchAlgorithmException, UnsupportedEncodingException {
StringBuilder passwordHash = new StringBuilder();
passwordHash.append('{').append(algorithm).append('}');
if (salt != null && !salt.isEmpty()) {
@@ -207,6 +213,7 @@ public final class PasswordUtil {
return passwordHash.toString();
}
+ @Nonnull
private static String generateSalt(int saltSize) {
SecureRandom random = new SecureRandom();
byte[] salt = new byte[saltSize];
@@ -221,7 +228,8 @@ public final class PasswordUtil {
* @param bytes the byte array
* @return the hex encoded string
*/
- public static String convertBytesToHex(byte[] bytes) {
+ @Nonnull
+ private static String convertBytesToHex(byte[] bytes) {
StringBuilder res = new StringBuilder(bytes.length * 2);
for (byte b : bytes) {
res.append(Text.hexTable[(b >> 4) & 15]);
@@ -236,7 +244,8 @@ public final class PasswordUtil {
* @param s the hex encoded string
* @return the byte array
*/
- public static byte[] convertHexToBytes(String s) {
+ @Nonnull
+ private static byte[] convertHexToBytes(String s) {
int len = s.length();
if (len % 2 != 0) {
throw new IllegalArgumentException("Not a hex encoded byte array: " + s);
@@ -249,8 +258,10 @@ public final class PasswordUtil {
}
return bytes;
}
-
- private static String generatePBKDF2(String pwd, String salt, String algorithm, int iterations, int keyLength) throws NoSuchAlgorithmException {
+
+ @Nonnull
+ private static String generatePBKDF2(@Nonnull String pwd, @Nonnull String salt,
+ @Nonnull String algorithm, int iterations, int keyLength) throws NoSuchAlgorithmException {
// for example PBKDF2WithHmacSHA1
SecretKeyFactory factory = SecretKeyFactory.getInstance(algorithm);
byte[] saltBytes = convertHexToBytes(salt);
@@ -264,7 +275,8 @@ public final class PasswordUtil {
}
}
- private static String generateDigest(String data, String algorithm, int iterations) throws UnsupportedEncodingException, NoSuchAlgorithmException {
+ @Nonnull
+ private static String generateDigest(@Nonnull String data, @Nonnull String algorithm, int iterations) throws UnsupportedEncodingException, NoSuchAlgorithmException {
byte[] bytes = data.getBytes(ENCODING);
MessageDigest md = MessageDigest.getInstance(algorithm);
@@ -287,7 +299,8 @@ public final class PasswordUtil {
* leading {@code algorithm} such as created by {@code buildPasswordHash}
* or if the extracted string isn't a supported algorithm.
*/
- private static String extractAlgorithm(String hashedPwd) {
+ @CheckForNull
+ private static String extractAlgorithm(@Nullable String hashedPwd) {
if (hashedPwd != null && !hashedPwd.isEmpty()) {
int end = hashedPwd.indexOf('}');
if (hashedPwd.charAt(0) == '{' && end > 0 && end < hashedPwd.length()-1) {
@@ -296,7 +309,7 @@ public final class PasswordUtil {
MessageDigest.getInstance(algorithm);
return algorithm;
} catch (NoSuchAlgorithmException e) {
- log.debug("Invalid algorithm detected " + algorithm);
+ log.debug("Invalid algorithm detected " + algorithm, e);
}
}
}
@@ -305,23 +318,28 @@ public final class PasswordUtil {
return null;
}
- private static String extractSalt(String hashedPwd, int start) {
- int end = hashedPwd.indexOf(DELIMITER, start);
- if (end > -1) {
- return hashedPwd.substring(start, end);
+ @CheckForNull
+ private static String extractSalt(@Nullable String hashedPwd, int start) {
+ if (hashedPwd != null) {
+ int end = hashedPwd.indexOf(DELIMITER, start);
+ if (end > -1) {
+ return hashedPwd.substring(start, end);
+ }
}
// no salt
return null;
}
- private static int extractIterations(String hashedPwd, int start) {
- int end = hashedPwd.indexOf(DELIMITER, start);
- if (end > -1) {
- String str = hashedPwd.substring(start, end);
- try {
- return Integer.parseInt(str);
- } catch (NumberFormatException e) {
- log.debug("Expected number of iterations. Found: " + str);
+ private static int extractIterations(@Nullable String hashedPwd, int start) {
+ if (hashedPwd != null) {
+ int end = hashedPwd.indexOf(DELIMITER, start);
+ if (end > -1) {
+ String str = hashedPwd.substring(start, end);
+ try {
+ return Integer.parseInt(str);
+ } catch (NumberFormatException e) {
+ log.debug("Expected number of iterations. Found: " + str, e);
+ }
}
}
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserManagerImplTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserManagerImplTest.java?rev=1519962&r1=1519961&r2=1519962&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserManagerImplTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserManagerImplTest.java Wed Sep 4 09:51:36 2013
@@ -16,18 +16,10 @@
*/
package org.apache.jackrabbit.oak.security.user;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertTrue;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.fail;
-
import java.security.Principal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
-
import javax.jcr.RepositoryException;
import javax.jcr.UnsupportedRepositoryOperationException;
@@ -46,6 +38,13 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
/**
* @since OAK 1.0
*/
@@ -114,14 +113,14 @@ public class UserManagerImplTest extends
try {
userMgr.setPassword(userTree, null, true);
fail("setting null password should fail");
- } catch (IllegalArgumentException e) {
+ } catch (NullPointerException e) {
// expected
}
try {
userMgr.setPassword(userTree, null, false);
fail("setting null password should fail");
- } catch (IllegalArgumentException e) {
+ } catch (NullPointerException e) {
// expected
}
}
Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/util/PasswordUtilTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/util/PasswordUtilTest.java?rev=1519962&r1=1519961&r2=1519962&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/util/PasswordUtilTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/util/PasswordUtilTest.java Wed Sep 4 09:51:36 2013
@@ -16,14 +16,16 @@
*/
package org.apache.jackrabbit.oak.spi.security.user.util;
-import org.junit.Test;
-
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import com.google.common.collect.ImmutableList;
+import org.junit.Before;
+import org.junit.Test;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -31,33 +33,32 @@ import static org.junit.Assert.fail;
public class PasswordUtilTest {
- private static List<String> PLAIN_PWDS = new ArrayList<String>();
- static {
- PLAIN_PWDS.add("pw");
- PLAIN_PWDS.add("PassWord123");
- PLAIN_PWDS.add("_");
- PLAIN_PWDS.add("{invalidAlgo}");
- PLAIN_PWDS.add("{invalidAlgo}Password");
- PLAIN_PWDS.add("{SHA-256}");
- PLAIN_PWDS.add("pw{SHA-256}");
- PLAIN_PWDS.add("p{SHA-256}w");
- PLAIN_PWDS.add("");
- }
-
- private static Map<String, String> HASHED_PWDS = new HashMap<String, String>();
- static {
- for (String pw : PLAIN_PWDS) {
- try {
- HASHED_PWDS.put(pw, PasswordUtil.buildPasswordHash(pw));
- } catch (Exception e) {
- // should not get here
- }
+ private List<String> plainPasswords;
+
+ private static Map<String, String> hashedPasswords;
+
+ @Before
+ public void before() throws Exception {
+ plainPasswords = ImmutableList.of(
+ "pw",
+ "PassWord123",
+ "_",
+ "{invalidAlgo}",
+ "{invalidAlgo}Password",
+ "{SHA-256}",
+ "pw{SHA-256}",
+ "p{SHA-256}w",
+ "");
+
+ hashedPasswords = new HashMap<String, String>();
+ for (String pw : plainPasswords) {
+ hashedPasswords.put(pw, PasswordUtil.buildPasswordHash(pw));
}
}
@Test
public void testBuildPasswordHash() throws Exception {
- for (String pw : PLAIN_PWDS) {
+ for (String pw : plainPasswords) {
String pwHash = PasswordUtil.buildPasswordHash(pw);
assertFalse(pw.equals(pwHash));
}
@@ -69,7 +70,7 @@ public class PasswordUtilTest {
l.add(new Integer[] {10, 5});
l.add(new Integer[] {-1, -1});
for (Integer[] params : l) {
- for (String pw : PLAIN_PWDS) {
+ for (String pw : plainPasswords) {
int saltsize = params[0];
int iterations = params[1];
@@ -88,7 +89,7 @@ public class PasswordUtilTest {
for (String invalid : invalidAlgorithms) {
try {
- String pwHash = PasswordUtil.buildPasswordHash("pw", invalid, PasswordUtil.DEFAULT_SALT_SIZE, PasswordUtil.DEFAULT_ITERATIONS);
+ PasswordUtil.buildPasswordHash("pw", invalid, PasswordUtil.DEFAULT_SALT_SIZE, PasswordUtil.DEFAULT_ITERATIONS);
fail("Invalid algorithm " + invalid);
} catch (NoSuchAlgorithmException e) {
// success
@@ -99,7 +100,7 @@ public class PasswordUtilTest {
@Test
public void testIsPlainTextPassword() throws Exception {
- for (String pw : PLAIN_PWDS) {
+ for (String pw : plainPasswords) {
assertTrue(pw + " should be plain text.", PasswordUtil.isPlainTextPassword(pw));
}
}
@@ -111,15 +112,15 @@ public class PasswordUtilTest {
@Test
public void testIsPlainTextForPwHash() throws Exception {
- for (String pwHash : HASHED_PWDS.values()) {
+ for (String pwHash : hashedPasswords.values()) {
assertFalse(pwHash + " should not be plain text.", PasswordUtil.isPlainTextPassword(pwHash));
}
}
@Test
public void testIsSame() throws Exception {
- for (String pw : HASHED_PWDS.keySet()) {
- String pwHash = HASHED_PWDS.get(pw);
+ for (String pw : hashedPasswords.keySet()) {
+ String pwHash = hashedPasswords.get(pw);
assertTrue("Not the same " + pw + ", " + pwHash, PasswordUtil.isSame(pwHash, pw));
}
@@ -137,8 +138,8 @@ public class PasswordUtilTest {
@Test
public void testIsNotSame() throws Exception {
String previous = null;
- for (String pw : HASHED_PWDS.keySet()) {
- String pwHash = HASHED_PWDS.get(pw);
+ for (String pw : hashedPasswords.keySet()) {
+ String pwHash = hashedPasswords.get(pw);
assertFalse(pw, PasswordUtil.isSame(pw, pw));
assertFalse(pwHash, PasswordUtil.isSame(pwHash, pwHash));
if (previous != null) {
@@ -152,10 +153,13 @@ public class PasswordUtilTest {
public void testPBKDF2WithHmacSHA1() throws Exception {
String algo = "PBKDF2WithHmacSHA1";
// test vector from http://tools.ietf.org/html/rfc6070
- String hash = PasswordUtil.generateHash(
- "pass\0word", algo,
- PasswordUtil.convertBytesToHex("sa\0lt".getBytes()), 4096);
- assertEquals("{PBKDF2WithHmacSHA1}7361006c74-4096-56fa6aa75548099dcc37d7f03425e0c3", hash);
+ String pw = "pass\0word";
+ int iterations = 4096;
+
+ String hash = PasswordUtil.buildPasswordHash(pw, algo, 5, iterations);
+ assertTrue(hash.startsWith("{PBKDF2WithHmacSHA1}"));
+ int cntOctets = hash.substring(hash.lastIndexOf('-')+1).length() / 2;
+ assertEquals(16, cntOctets);
}
}
\ No newline at end of file