Package com.knife.security

Source Code of com.knife.security.PasswordUtil

/*
*  Copyright 2012 Anton Van Zyl. http://code.google.com/p/java-swiss-knife/
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*       http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*  under the License.
*/
package com.knife.security;

import java.util.Random;
import java.util.regex.Pattern;

import org.apache.commons.lang.StringUtils;

import com.knife.security.exception.InvalidPasswordLength;

/**
* This is the password utilities that I use the most. <br/>
* <br/>
* Please visit <a
* href="http://code.google.com/p/java-swiss-knife/">Java-Swiss-Knife</a> and
* comment, rate, contribute or raise a issue/enhancement for my library. <br/>
*
* @author Anton Van Zyl
*
*/
public final class PasswordUtil {

  // Bonus scheme for passwords
  private static final int Excess = 3;
  private static final int Upper = 4;
  private static final int Numbers = 3;
  private static final int Symbols = 5;
  private static final String regex = "[!,@,#,$,%,^,&,*,?,_,~]+";

  //@formatter:off
    protected static char[] lowerCaseAlpa =
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n'
        'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
    }
    protected static char[] upperCaseAlpha =
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N'
        'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
    }
    protected static char[] numbers =
        '1', '2', '3', '4', '5', '6', '7', '8', '9','0', ' ',
    }
    protected static char[] symbols =
        '+', '-', '@','!','#','$','%','^','&','*','?','_','~'
    }
    //@formatter:on

  /**
   * This will not generate a readable word but a sequence of chars at the
   * specified length and complexity. The character selection is listed below
   * that will be used when generating a valid password:
   *
   * <pre>
   * <code>
   *   protected static char[] lowerCaseAlpa = { 
   *         'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 
   *         'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
   *     }; 
   *     protected static char[] upperCaseAlpha = { 
   *         'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 
   *         'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
   *     }; 
   *     protected static char[] numbers = { 
   *         '1', '2', '3', '4', '5', '6', '7', '8', '9','0', ' ',
   *     }; 
   *     protected static char[] symbols = { 
   *         '+', '-', '@','!','#','$','%','^','&','*','?','_','~'
   *     }; 
   * </code>
   * </pre>
   *
   * @param complexity
   *            - The complexity that the password will be generated at, this
   *            will always be equal to or above the specified complexity
   * @return The password that is generated
   */
  public static String generateRandomPassword(PasswordComplexity complexity) {

    StringBuilder password = new StringBuilder(generatePassword(complexity));

    try {
      boolean foundPassword = false;
      while (foundPassword == false) {

        PasswordComplexity comp = checkPasswordStrength(password.toString(), complexity.getPasswordLength());
        if (comp.ordinal() >= complexity.ordinal()) {
          foundPassword = true;
        } else {
          new StringBuilder(generatePassword(complexity));
        }

      }
    } catch (InvalidPasswordLength e) {
      e.printStackTrace();
    }

    return password.toString();
  }

  /**
   * Generates the password
   * @param complexity
   * @return password
   */
  private static String generatePassword(PasswordComplexity complexity) {
    StringBuilder password = new StringBuilder();
    Random random = new Random();
    switch (complexity) {
    case WEAK:
      for (int i = 0; i < complexity.getPasswordLength(); i++) {
        password.append(lowerCaseAlpa[random.nextInt(lowerCaseAlpa.length)]);
      }
      break;
    case BELOW_AVERAGE:
      for (int i = 0; i < (complexity.getPasswordLength() - 1); i++) {
        password.append(lowerCaseAlpa[random.nextInt(lowerCaseAlpa.length)]);
      }
      password.append(numbers[random.nextInt(numbers.length)]);
      break;
    case AVERAGE:
      for (int i = 0; i < (complexity.getPasswordLength() / 2); i++) {
        password.append(lowerCaseAlpa[random.nextInt(lowerCaseAlpa.length)]);
        password.append(upperCaseAlpha[random.nextInt(upperCaseAlpha.length)]);
      }
      while (password.length() < complexity.getPasswordLength()) {
        password.append(lowerCaseAlpa[random.nextInt(lowerCaseAlpa.length)]);
      }
      break;
    case ABOVE_AVERAGE:
      for (int i = 0; i < ((complexity.getPasswordLength()) / 2) - 1; i++) {
        password.append(lowerCaseAlpa[random.nextInt(lowerCaseAlpa.length)]);
        password.append(upperCaseAlpha[random.nextInt(upperCaseAlpha.length)]);
      }
      password.append(numbers[random.nextInt(numbers.length)]);
      while (password.length() < complexity.getPasswordLength()) {
        password.append(lowerCaseAlpa[random.nextInt(lowerCaseAlpa.length)]);
      }
      break;
    case STRONG:
      for (int i = 0; i < (complexity.getPasswordLength() / 3); i++) {
        password.append(lowerCaseAlpa[random.nextInt(lowerCaseAlpa.length)]);
        password.append(upperCaseAlpha[random.nextInt(upperCaseAlpha.length)]);
        password.append(numbers[random.nextInt(numbers.length)]);
      }
      while (password.length() < complexity.getPasswordLength()) {
        password.append(upperCaseAlpha[random.nextInt(upperCaseAlpha.length)]);
      }
      break;
    case SECURE:
      for (int i = 0; i < (complexity.getPasswordLength() / 4); i++) {
        password.append(lowerCaseAlpa[random.nextInt(lowerCaseAlpa.length)]);
        password.append(upperCaseAlpha[random.nextInt(upperCaseAlpha.length)]);
        password.append(numbers[random.nextInt(numbers.length)]);
        password.append(symbols[random.nextInt(symbols.length)]);
      }
      while (password.length() < complexity.getPasswordLength()) {
        password.append(symbols[random.nextInt(symbols.length)]);
      }
      break;
    }
    return password.toString();
  }

  /**
   * This will calculate the password input strength and return a enumeration
   * representing the outcome of the calculation.
   *
   *
   * @param passwordInput
   *            - the password to test against
   * @param minPasswordLength
   *            - the minimum password length allowed (This is used in the
   *            calculation and is better to define)
   * @return <code>PasswordComplexity</code> enumeration defining the password
   *         complexity state.
   * @throws InvalidPasswordLength
   *             - when the entered password is below the specified length
   */
  public static PasswordComplexity checkPasswordStrength(String passwordInput, int minPasswordLength) throws InvalidPasswordLength {

    if (passwordInput == null) {
      throw new NullPointerException("checkPasswordStrength: passwordInput is NULL");
    }

    int baseScore;
    if (passwordInput.length() >= minPasswordLength) {
      baseScore = 50;
      Password password = analyzePassword(passwordInput, minPasswordLength);
      baseScore = calculateComplexity(password, baseScore);
    } else {
      throw new InvalidPasswordLength("The password is incorrect length [minPasswordLength=" + minPasswordLength + ";passwordInputLength=" + passwordInput.length() + ";]");
    }

    return PasswordComplexity.calculateComplexity(baseScore);
  }

  /**
   * Analyse a input string and creates a score to be calculated with. This is
   * build by extracting the different characters that exist in the string.
   *
   * @param passwordInput
   *            - The string that is the password
   * @param minPasswordLength
   *            - The length the password needs to be.
   * @return - Password object that contains the count
   */
  private static Password analyzePassword(final String passwordInput, final int minPasswordLength) {
    Password password = new Password();

    for (char value : passwordInput.toCharArray()) {
      String stringValue = String.valueOf(value);
      if (StringUtils.isNumeric(stringValue)) {
        password.numbers++;
      } else if (StringUtils.isAllUpperCase(stringValue)) {
        password.upper++;
      } else if (Pattern.matches(regex, stringValue) || value == ' ') {
        password.symbols++;
      }
    }

    password.excess = passwordInput.length() - minPasswordLength;

    if (password.upper > 0 && password.numbers > 0 && password.symbols > 0) {
      password.bonusCombo = 25;
    } else if ((password.upper > 0 && password.numbers > 0) || (password.upper > 0 && password.symbols > 0) || (password.numbers > 0 && password.symbols > 0)) {
      password.bonusCombo = 15;
    }

    if (StringUtils.isAllLowerCase(passwordInput)) {
      password.bonusFlatLower = -15;
    }

    if (StringUtils.isNumeric(passwordInput)) {
      password.bonusFlatNumber = -35;
    }

    return password;
  }

  /**
   * Calculates the complexity of the password
   *
   * @param password
   *            - The password a object that holds the score
   * @param baseScore
   *            - the base on which the score proceeds
   * @return the score that the password received
   */
  private static int calculateComplexity(final Password password, final int baseScore) {
    int result = baseScore + (password.excess * Excess) + (password.upper * Upper) + (password.numbers * Numbers) + (password.symbols * Symbols) + password.bonusCombo
        + password.bonusFlatLower + password.bonusFlatNumber;
    return result;

  }

}
TOP

Related Classes of com.knife.security.PasswordUtil

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.