boolean hasRequiredCharacterMix(String str) { // Must have at least 3 of: upper alpha, lower alpha, numeric, special int cnt = 0; Perl5Matcher matcher = RegexpUtil.getMatcher(); for (Pattern pat : charPats) { if (matcher.contains(str, pat)) { cnt++; } } return cnt >= 3; }
/** * Library of Congress password rules: * * <p>- The system must enforce a minimum password length of 8 characters for user passwords. * * <p>- The system must enforce at least three (3) of the following password complexity rules for * user passwords: (a) at least 1 upper case alphabetic character, (b) at least 1 lower case * alphabetic character, (c) at least 1 numeric character, (d) at least 1 special character. * * <p>- The system must prevent passwords with consecutive repeated characters for user accounts. * * <p>- The system must prevent the reuse of the 11 most recently used passwords for a particular * user account for user accounts. * * <p>- The system must prevent the user from changing his or her password more than one time per * day. * * <p>- The system must ensure that user passwords expire if not changed every sixty (60) days with * the exception of Public E-Authentication Level 1 or 2 systems, per NIST SP 800-63, which ensure * that user passwords expire if not changed annually. * * <p>- The system must provide a warning message seven (7) days before the user password expires */ public class LCUserAccount extends UserAccount { static final long MIN_PASSWORD_CHANGE_INTERVAL = 1 * Constants.DAY; static final long MAX_PASSWORD_CHANGE_INTERVAL = 60 * Constants.DAY; static final long PASSWORD_CHANGE_REMINDER_INTERVAL = 7 * Constants.DAY; static final long INACTIVITY_LOGOUT = 15 * Constants.MINUTE; static final int HISTORY_SIZE = 11; static final int MAX_FAILED_ATTEMPTS = 3; static final long MAX_FAILED_ATTEMPT_WINDOW = 15 * Constants.MINUTE; static final long MAX_FAILED_ATTEMPT_RESET_INTERVAL = 15 * Constants.MINUTE; static final String HASH_ALGORITHM = "SHA-256"; public LCUserAccount(String name) { super(name); } public String getType() { return "LC"; } protected int getHistorySize() { return HISTORY_SIZE; } protected String getDefaultHashAlgorithm() { return HASH_ALGORITHM; } public long getInactivityLogout() { return INACTIVITY_LOGOUT; } protected int getMinPasswordLength() { return 8; } protected long getMinPasswordChangeInterval() { return MIN_PASSWORD_CHANGE_INTERVAL; } protected long getMaxPasswordChangeInterval() { return MAX_PASSWORD_CHANGE_INTERVAL; } protected long getPasswordChangeReminderInterval() { return PASSWORD_CHANGE_REMINDER_INTERVAL; } protected int getMaxFailedAttempts() { return MAX_FAILED_ATTEMPTS; } protected long getFailedAttemptWindow() { return MAX_FAILED_ATTEMPT_WINDOW; } protected long getFailedAttemptResetInterval() { return MAX_FAILED_ATTEMPT_RESET_INTERVAL; } /** Return the hash algorithm to be used for new accounts */ @Override protected void checkLegalPassword(String newPwd, String hash, boolean isAdmin) throws IllegalPasswordChange { super.checkLegalPassword(newPwd, hash, isAdmin); if (StringUtil.hasRepeatedChar(newPwd)) { throw new IllegalPassword("Password may not contain consecutive repeated characters"); } if (!hasRequiredCharacterMix(newPwd)) { throw new IllegalPassword( "Password must contain mix of upper, lower, numeric and special characters"); } } static Pattern[] charPats = { RegexpUtil.uncheckedCompile("[a-z]", Perl5Compiler.READ_ONLY_MASK), RegexpUtil.uncheckedCompile("[A-Z]", Perl5Compiler.READ_ONLY_MASK), RegexpUtil.uncheckedCompile("[0-9]", Perl5Compiler.READ_ONLY_MASK), RegexpUtil.uncheckedCompile("[" + SPECIAL_CHARS + "]", Perl5Compiler.READ_ONLY_MASK) }; boolean hasRequiredCharacterMix(String str) { // Must have at least 3 of: upper alpha, lower alpha, numeric, special int cnt = 0; Perl5Matcher matcher = RegexpUtil.getMatcher(); for (Pattern pat : charPats) { if (matcher.contains(str, pat)) { cnt++; } } return cnt >= 3; } public static class Factory extends UserAccount.Factory { public UserAccount newUser(String name, AccountManager acctMgr, Configuration config) { UserAccount acct = new LCUserAccount(name); acct.init(acctMgr, config); return acct; } } }