summaryrefslogtreecommitdiffstats
path: root/src/main/java/com/gitblit/utils/PasswordHash.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/gitblit/utils/PasswordHash.java')
-rw-r--r--src/main/java/com/gitblit/utils/PasswordHash.java60
1 files changed, 50 insertions, 10 deletions
diff --git a/src/main/java/com/gitblit/utils/PasswordHash.java b/src/main/java/com/gitblit/utils/PasswordHash.java
index 5ccfab49..13747805 100644
--- a/src/main/java/com/gitblit/utils/PasswordHash.java
+++ b/src/main/java/com/gitblit/utils/PasswordHash.java
@@ -16,6 +16,8 @@
package com.gitblit.utils;
+import java.util.Arrays;
+
/**
* This is the superclass for classes responsible for handling password hashing.
*
@@ -35,7 +37,8 @@ public abstract class PasswordHash {
*/
enum Type {
MD5,
- CMD5
+ CMD5,
+ PBKDF2
}
/**
@@ -70,6 +73,8 @@ public abstract class PasswordHash {
return new PasswordHashMD5();
case CMD5:
return new PasswordHashCombinedMD5();
+ case PBKDF2:
+ return new PasswordHashPbkdf2();
default:
return null;
}
@@ -100,17 +105,31 @@ public abstract class PasswordHash {
* Test if a given string is a hashed password entry. This method simply checks if the
* given string is prefixed by a known hash type identifier.
*
- * @param password
+ * @param storedPassword
* A stored user password.
* @return True if the given string is detected to be hashed with a known hash type,
* false otherwise.
*/
- public static boolean isHashedEntry(String password) {
- return null != getEntryType(password);
+ public static boolean isHashedEntry(String storedPassword) {
+ return null != getEntryType(storedPassword);
}
-
-
+
+
+ /**
+ * Convert the given password to a hashed password entry to be stored in the user table.
+ * The resulting string is prefixed by the hashing scheme type followed by a colon:
+ * TYPE:theactualhashinhex
+ *
+ * @param password
+ * Password to be hashed.
+ * @param username
+ * User name, only used for the Combined-MD5 (user+MD5) hashing type.
+ * @return
+ * Hashed password entry to be stored in the user table.
+ */
+ abstract public String toHashedEntry(char[] password, String username);
+
/**
* Convert the given password to a hashed password entry to be stored in the user table.
* The resulting string is prefixed by the hashing scheme type followed by a colon:
@@ -123,7 +142,10 @@ public abstract class PasswordHash {
* @return
* Hashed password entry to be stored in the user table.
*/
- abstract public String toHashedEntry(String password, String username);
+ public String toHashedEntry(String password, String username) {
+ if (password == null) throw new IllegalArgumentException("The password argument may not be null when hashing a password.");
+ return toHashedEntry(password.toCharArray(), username);
+ }
/**
* Test if a given password (and user name) match a hashed password.
@@ -145,7 +167,8 @@ public abstract class PasswordHash {
if (hashedEntry == null || type != PasswordHash.getEntryType(hashedEntry)) return false;
if (password == null) return false;
- String hashed = toHashedEntry(String.valueOf(password), username);
+ String hashed = toHashedEntry(password, username);
+ Arrays.fill(password, Character.MIN_VALUE);
return hashed.equalsIgnoreCase(hashedEntry);
}
@@ -159,6 +182,8 @@ public abstract class PasswordHash {
if (indexOfSeparator <= 0) return null;
String typeId = hashedEntry.substring(0, indexOfSeparator);
+ // Compatibility with type id "PBKDF2WITHHMACSHA256", which is also handled by PBKDF2 type.
+ if (typeId.equalsIgnoreCase("PBKDF2WITHHMACSHA256")) return Type.PBKDF2;
try {
return Type.valueOf(typeId.toUpperCase());
}
@@ -169,7 +194,7 @@ public abstract class PasswordHash {
static String getEntryValue(String hashedEntry) {
if (hashedEntry == null) return null;
int indexOfSeparator = hashedEntry.indexOf(':');
- return hashedEntry.substring(indexOfSeparator +1, hashedEntry.length());
+ return hashedEntry.substring(indexOfSeparator +1);
}
@@ -184,6 +209,14 @@ public abstract class PasswordHash {
super(Type.MD5);
}
+ // To keep the handling identical to how it was before, and therefore not risk invalidating stored passwords,
+ // for MD5 the (String,String) variant of the method is the one implementing the hashing.
+ @Override
+ public String toHashedEntry(char[] password, String username) {
+ if (password == null) throw new IllegalArgumentException("The password argument may not be null when hashing a password.");
+ return toHashedEntry(new String(password), username);
+ }
+
@Override
public String toHashedEntry(String password, String username) {
if (password == null) throw new IllegalArgumentException("The password argument may not be null when hashing a password.");
@@ -201,9 +234,16 @@ public abstract class PasswordHash {
super(Type.CMD5);
}
+ // To keep the handling identical to how it was before, and therefore not risk invalidating stored passwords,
+ // for Combined-MD5 the (String,String) variant of the method is the one implementing the hashing.
+ @Override
+ public String toHashedEntry(char[] password, String username) {
+ if (password == null) throw new IllegalArgumentException("The password argument may not be null when hashing a password.");
+ return toHashedEntry(new String(password), username);
+ }
@Override
public String toHashedEntry(String password, String username) {
- if (password == null) throw new IllegalArgumentException("The password argument may not be null when hashing a password with Combined-MD5.");
+ if (password == null) throw new IllegalArgumentException("The password argument may not be null when hashing a password.");
if (username == null) throw new IllegalArgumentException("The username argument may not be null when hashing a password with Combined-MD5.");
if (StringUtils.isEmpty(username)) throw new IllegalArgumentException("The username argument may not be empty when hashing a password with Combined-MD5.");
return type.name() + ":"