import java.text.MessageFormat;
import java.util.Properties;
import java.util.Random;
+import java.util.regex.Pattern;
import org.apache.commons.codec.digest.Crypt;
import org.apache.commons.codec.digest.DigestUtils;
import org.mxchange.jcontacts.contact.Contact;
/**
* Password alphabet
*/
- private static final String PASSWORD_ALPHABET = "abcdefghijklmnopqrstuvwxzyABCDEFGHIJKLMNOPQRSTUVWXZY0123456789-/?!_+#@"; //NOI18N
+ private static final String PASSWORD_ALPHABET =
+ UserUtils.PASSWORD_ALPHABET_PARTS[0] +
+ UserUtils.PASSWORD_ALPHABET_PARTS[1] +
+ UserUtils.PASSWORD_ALPHABET_PARTS[2] +
+ UserUtils.PASSWORD_ALPHABET_PARTS[3];
+
+ /**
+ * Password alphabet parts
+ */
+ private static final String[] PASSWORD_ALPHABET_PARTS = {
+ // lower-case
+ "abcdefghijklmnopqrstuvwxyz", //NOI18N
+
+ // upper-case
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ", //NOI18N
+
+ // numbers
+ "0123456789", //NOI18N
+
+ // characters
+ "!\"$%&/()=?{[]}@+*#-_,.;:<|>" //NOI18N
+ };
/**
* Minimum password length
RANDOM_NUMBER_GENERATOR = new SecureRandom();
}
+ /**
+ * Calculates entropy value for given password, higher means better. This
+ * method is based on
+ * http://stackoverflow.com/questions/14591701/how-to-check-password-strength-in-vaadin
+ * <p>
+ * @param password Clear text password
+ * <p>
+ * @return Entropy factor
+ */
+ public static double calculateEntropyFactor (final String password) {
+ // Should not be null
+ if (null == password) {
+ // Throw NPE
+ throw new NullPointerException("password is null"); //NOI18N
+ }
+
+ // Calculate it
+ double entropyFactor = password.length() * Math.log10(PASSWORD_ALPHABET.length()) / Math.log10(2);
+
+ // Return it
+ return entropyFactor;
+ }
+
/**
* Creates a pseudo-random password with given length
* <p>
// Start creating it
for (int i = 0; i < length; i++) {
+ // Take random part
+ String alphabet = PASSWORD_ALPHABET_PARTS[RANDOM_NUMBER_GENERATOR.nextInt(PASSWORD_ALPHABET_PARTS.length)];
+
// Generate random number
- int pos = RANDOM_NUMBER_GENERATOR.nextInt(PASSWORD_ALPHABET.length());
+ int pos = RANDOM_NUMBER_GENERATOR.nextInt(alphabet.length());
// Get char at this position and add it to the final password
- password.append(String.valueOf(PASSWORD_ALPHABET.charAt(pos)));
+ password.append(String.valueOf(alphabet.charAt(pos)));
}
// Should have the wanted length
return password.toString();
}
+ /**
+ * Determines given password's strength: 0 = bad, 100 = best. This method is
+ * based on
+ * http://stackoverflow.com/questions/1614811/how-do-i-measure-the-strength-of-a-password
+ * <p>
+ * @param password Clear-text password
+ * <p>
+ * @return Strength of password
+ */
+ public static float determinePasswordStrength (final String password) {
+ // Should not be null
+ if (null == password) {
+ // Throw NPE
+ throw new NullPointerException("password is null"); //NOI18N
+ } else if (password.isEmpty()) {
+ // Is empty
+ return 0.0f;
+ }
+
+ // Init score
+ float score = 0.0f;
+
+ //password length
+ score += password.length() * calculateEntropyFactor(password);
+
+ //password has 3 numbers
+ if (Pattern.matches("/(.*[0-9].*[0-9].*[0-9])/", password)) { //NOI18N
+ score += 5;
+ }
+
+ //password has 2 symbols
+ if (Pattern.matches("/(.*[!,@,#,$,%,^,&,*,?,_,~].*[!,@,#,$,%,^,&,*,?,_,~])/", password)) { //NOI18N
+ score += 5;
+ }
+
+ //password has Upper and Lower chars
+ if (Pattern.matches("/([a-z].*[A-Z])|([A-Z].*[a-z])/", password)) { //NOI18N
+ score += 10;
+ }
+
+ //password has number and chars
+ if (Pattern.matches("/([a-zA-Z])/", password) && Pattern.matches("/([0-9])/", password)) { //NOI18N
+ score += 15;
+ }
+
+ //password has number and symbol
+ if (Pattern.matches("/([!,@,#,$,%,^,&,*,?,_,~])/", password) && Pattern.matches("/([0-9])/", password)) { //NOI18N
+ score += 15;
+ }
+
+ //password has char and symbol
+ if (Pattern.matches("/([!,@,#,$,%,^,&,*,?,_,~])/", password) && Pattern.matches("/([a-zA-Z])/", password)) { //NOI18N
+ score += 15;
+ }
+
+ //password is just a nubers or chars
+ if (Pattern.matches("/^[a-zA-Z]+$/", password) || Pattern.matches("/^[0-9]+$/", password)) { //NOI18N
+ score -= 10;
+ }
+
+ // Larger than 100 is not allowed
+ score = Math.max(score, 100.0f);
+
+ // Return it
+ return score;
+ }
+
/**
* Hashes given user password and adds a salt to it
* <p>
* @return Generated key
*/
public static String generatedConfirmationKey (final User user) {
- // Generates random string by creating a random, encrypted password
+ /**
+ * Generates random string by creating a random, encrypted password
+ * which gives nice entropy to start with.
+ */
StringBuilder key = new StringBuilder(encryptPassword(generateRandomUserName()));
// Is user set?