All Downloads are FREE. Search and download functionalities are using the official Maven repository.

rodeo.password.pgencheck.PasswordChecker Maven / Gradle / Ivy

Go to download

This project provides classes to create and validate passwords. A number of criteria can be provided (minimum and maximum length, presence of certain character types, etc.) to validate and create passwords. Any Unicode character can be used in the generation and validation of passwords.

The newest version!
package rodeo.password.pgencheck;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static rodeo.password.pgencheck.ErrorMessages.AT_LEAST_ONE_CHAR;
import static rodeo.password.pgencheck.ErrorMessages.NOT_ENOUGH_CHARACTERS;
import static rodeo.password.pgencheck.ErrorMessages.NO_CHECKER_CHAR_SET_PROVIDED;
import static rodeo.password.pgencheck.ErrorMessages.MAX_BIGGER_THAN_MIN;

/**
 * Validate passwords according to predefined criteria.
 * 

* The following criteria are available: *

    *
  • minimum length;
  • *
  • maximum length;
  • *
  • * constraints on characters composing the password: *
      *
    • character must belong to a predefined group of characters;
    • *
    • minimum and maximum number of characters per group can be specified.
    • *
    *
  • *
*/ public final class PasswordChecker extends PasswordData { private final int minLength; private final int maxLength; private PasswordChecker( int minLength, int maxLength, List charGroups, List groupMinCounts, List groupMaxCounts) { super(charGroups, groupMinCounts, groupMaxCounts); this.minLength = minLength; this.maxLength = maxLength; } /** * Create a factory to specify password validation criteria and create a PasswordChecker object. * @return an internal PasswordChecker factory * @see Factory */ public static Factory factory() { return new Factory(); } /** * Get the minimum length required for a password to be accepted. * @return the minimum length required for a password to be accepted */ public int getMinLength() { return minLength; } /** * Get the maximum length required for a password to be accepted. * @return the maximum length required for a password to be accepted */ public int getMaxLength() { return maxLength; } /** * Check if a password can be validated against the specified criteria and return true * if that's the case. * @param password to be validated * @return true if password matches the criteria, false otherwise */ public boolean quickCheck(String password) { if (password.length() < minLength) return false; if (password.length() > maxLength) return false; for (int codePoint: password.codePoints().toArray()) if (getAllChars().indexOf(codePoint) == -1) return false; var charCounts = getCharacterTypeCounts(password); for (int i = 0; i < groupMinCounts().size(); ++i) { int count = charCounts.get(i); if (count < groupMinCounts().get(i) || (groupMaxCounts().get(i) != 0 && count > groupMaxCounts().get(i))) return false; } return true; } private Map getCharacterTypeCounts(String password) { var counts = new HashMap(); for (int i = 0; i < charGroups().size(); ++i) counts.put(i, 0); password.codePoints().forEach(codePoint -> { for (int i = 0; i < charGroups().size(); ++i) if (charGroups().get(i).indexOf(codePoint) != - 1) counts.put(i, counts.get(i) + 1); }); return counts; } /** * Check if a password can be validated against the specified criteria and return the first error encountered * if any or PasswordCheckStatus.OK otherwise. *

* Criteria are checked in this order: *

    *
  • minimum length of password;
  • *
  • maximum length of password;
  • *
  • illegal characters;
  • *
  • not enough characters from a certain group;
  • *
  • too many characters form a certain group.
  • *
* @param password to be validated * @return PasswordCheckStatus.OK if password matches the criteria, otherwise a code * for the first error encountered * @see PasswordCheckStatus */ public PasswordCheckStatus check(String password) { if (password.length() < minLength) return PasswordCheckStatus.TOO_SHORT; if (password.length() > maxLength) return PasswordCheckStatus.TOO_LONG; for (int codePoint: password.codePoints().toArray()) if (getAllChars().indexOf(codePoint) == -1) return PasswordCheckStatus.ILLEGAL_CHARACTER; var charCounts = getCharacterTypeCounts(password); for (int i = 0; i < groupMinCounts().size(); ++i) { int count = charCounts.get(i); if (count < groupMinCounts().get(i)) return PasswordCheckStatus.NOT_ENOUGH_OF_CHARACTER_GROUP; if (groupMaxCounts().get(i) > 0 && count > groupMaxCounts().get(i)) return PasswordCheckStatus.TOO_MANY_OF_CHARACTER_GROUP; } return PasswordCheckStatus.OK; } /** * Check if a password can be validated against the specified criteria and return a list of all the problems * encountered. This list is empty if there is no error. * @param password to be validated * @return a list of all the errors encountered while validating the password or an empty list if the * password matches all the criteria * @see PasswordCheckError */ public List fullCheck(String password) { var errors = new ArrayList(); if (password.length() < minLength) errors.add(PasswordCheckError.tooShort()); if (password.length() > maxLength) errors.add(PasswordCheckError.tooLong()); password.codePoints().forEach(codePoint -> { if (getAllChars().indexOf(codePoint) == -1) errors.add(PasswordCheckError.illegalCharacter(codePoint)); }); var charCounts = getCharacterTypeCounts(password); for (int i = 0; i < groupMinCounts().size(); ++i) { int count = charCounts.get(i); if (count < groupMinCounts().get(i)) errors.add(PasswordCheckError.notEnoughOfCharacterType(i, charGroups().get(i), groupMinCounts().get(i), charCounts.get(i))); if (groupMaxCounts().get(i) > 0 && count > groupMaxCounts().get(i)) errors.add(PasswordCheckError.tooManyOfCharacterType(i, charGroups().get(i), groupMaxCounts().get(i), charCounts.get(i))); } return errors; } /** * Internal factory to create PasswordCheckers. *

* This factory class allows you to build a PasswordChecker using a fluent interface. You create a * Factory by calling {@link PasswordChecker#factory() PasswordChecker.factory()}. * Once all the criteria have been specified, you call the {@link #create() create} function * to create a PasswordChecker object. */ public static final class Factory extends AbstractFactory { private int minLength = 16; private int maxLength = 64; private Factory() { } /** * Sets the minimum and maximum password lengths allowed. * @param minLength the password minimum length * @param maxLength the password maximum length * @return this factory */ public Factory setMinMaxLength(int minLength, int maxLength) { if (minLength < 1) throw new IllegalArgumentException(AT_LEAST_ONE_CHAR + minLength); if (maxLength < minLength) throw new IllegalArgumentException(MAX_BIGGER_THAN_MIN + maxLength + " < " + minLength); this.minLength = minLength; this.maxLength = maxLength; return this; } /** * Create a PasswordChecker according to the specified criteria. * @return a new PasswordChecker matching the specified criteria * @throws IllegalStateException if no character group has been specified * @throws IllegalStateException if validation would be impossible because the minimum count requirements * on character groups would exceed the maximum length allowed for the password */ public PasswordChecker create() { if (charGroups().isEmpty()) throw new IllegalStateException(NO_CHECKER_CHAR_SET_PROVIDED); if (isSetCountSumLargerThanMaxPasswordCount()) throw new IllegalStateException(NOT_ENOUGH_CHARACTERS); return new PasswordChecker( minLength, maxLength, charGroupsCopy(), groupMinCountsCopy(), groupMaxCountsCopy()); } private boolean isSetCountSumLargerThanMaxPasswordCount() { int sum = 0; for (int count: groupMinCounts()) sum += count; return sum > maxLength; } @Override Factory getThis() { return this; } // !! The 4 methods below are only overloaded for documentation purpose !! /** * Add a group of allowed characters in the composition of the password. * @param charGroup a String containing all characters allowed in this group * @return this factory * @throws IllegalArgumentException if the character group contains duplicates or if the character group * contains characters already present in other character groups, unless duplicates have been explicitly * allowed by calling disallowDuplicateCharacters(false) * @see #disallowDuplicateCharacters(boolean) */ @Override public Factory addCharGroup(String charGroup) { return super.addCharGroup(charGroup); } /** * Add a group of allowed characters in the composition of the password and specifies a minimum character * count. * @param charGroup a String containing all characters allowed in this group * @param minCount minimum number of characters from this group that must be present in the password * @return this factory * @throws IllegalArgumentException if the character group contains duplicates or if the character group * contains characters already present in other character groups, unless duplicates have been explicitly * allowed by calling disallowDuplicateCharacters(false) * @throws IllegalArgumentException if minCount < 0 * @see #disallowDuplicateCharacters(boolean) */ @Override public Factory addCharGroup(String charGroup, int minCount) { return super.addCharGroup(charGroup, minCount, 0); } /** * Add a group of allowed characters in the composition of the password and specifies a minimum and maximum * character count. * @param charGroup a String containing all characters allowed in this group * @param minCount minimum number of characters from this group that must be present in the password * @param maxCount maximum number of characters from this group allowed in the password; a value of * 0 (zero) means "unlimited" (same as calling * {@link #addCharGroup(String, int) addCharGroup(String, int)}) * @return this factory * @throws IllegalArgumentException if the character group contains duplicates or if the character group * contains characters already present in other character groups, unless duplicates have been explicitly * allowed by calling disallowDuplicateCharacters(false) * @throws IllegalArgumentException if minCount < 0, or maxCount < 0, or * maxCount < minCount (unless maxCount == 0) * @see #disallowDuplicateCharacters(boolean) */ @Override public Factory addCharGroup(String charGroup, int minCount, int maxCount) { return super.addCharGroup(charGroup, minCount, maxCount); } /** * Disallow or allow duplicates inside character groups and between character groups. Allowing duplicate is * usually unnecessary and error-prone. * @param disallowDuplicateCharacters true if duplicate characters should be disallowed (default), * false otherwise * @return this factory */ @Override public Factory disallowDuplicateCharacters(boolean disallowDuplicateCharacters) { return super.disallowDuplicateCharacters(disallowDuplicateCharacters); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy