The Passay API consists of 3 core components:
Rule
- one or more rules define a password policy rule setPasswordValidator
- validates a password against a rule setPasswordGenerator
- produces passwords that satisfy a given rule set
Rule overview
Rules are the building blocks for both password validation and generation, and it is helpful to review the ruleset that passay provides out of the box. There are two broad categories of rules:
- Positive match require that passwords satisfy a rule
- Negative match reject passwords that satisfy a rule
The following sections briefly describe the available rules in both categories.
Positive matching rules
AllowedCharacterRule
- requires passwords to contain all of a set of charactersAllowedRegexRule
- requires passwords to conform to a regular expressionCharacterCharacteristicsRule
- requires passwords to contain M of N classes of characters; for example, 3 of 4 of the following: digit, upper-case letters, lower-case letters, symbolsCharacterRule
- requires passwords to contain at least N characters from a given character set (e.g. digits, upper-case letters, lowercase-letters, symbols)LengthRule
- requires passwords to meet a minimum required lengthLengthComplexityRule
- requires passwords to meet a specific set of rules based on the length of the password. For example, passwords between 8-12 characters long must contain both a number and symbol. Passwords 13 characters and longer must only contain alphabetical characters
Negative matching rules
- Dictionary rules
DictionaryRule
- rejects passwords that match an entry in a dictionary (exact match semantics)DictionarySubstringRule
- rejects passwords that contain an entry in a dictionary (substring match semantics)DigestDictionaryRule
- rejects passwords that match a digested entry in a dictionary (hash/digest comparison)
- History rules
HistoryRule
- rejects passwords that match previous passwords (cleartext comparison)DigestHistoryRule
- rejects passwords that match previous password digests (hash/digest comparison)
CharacterOccurrencesRule
- rejects passwords that contain too many occurances of the same characterIllegalCharacterRule
- rejects passwords that contain any of a set of charactersIllegalRegexRule
- rejects passwords that conform to a regular expressionIllegalSequenceRule
- rejects passwords that contain a sequence of N characters (e.g. 12345)NumberRangeRule
- rejects passwords that contain any number within a defined range (e.g. 1000-9999)- Source rules
SourceRule
- rejects passwords that match those from another source (cleartext comparison)DigestSourceRule
- rejects passwords that match the digest of those from another source (hash/digest comparison)
RepeatCharacterRegexRule
- rejects passwords that contain a repeated ASCII characterRepeatCharactersRule
- rejects passwords that contain multiple sequences of repeating charactersUsernameRule
- rejects passwords that contain the username of the user providing the passwordWhitespaceRule
- rejects passwords that contain whitespace characters
Password validation
Password validation involves creating a PasswordValidator
from a rule set, which is simply a list of Rule
objects.
Consider the following simple password policy:
- Length of 8 to 16 characters
- Must contain at least one of the following: upper case, lower case, digit, and symbol
- No whitespace characters
The following code excerpt constructs a validator that enforces the policy.
Advanced validation: customizing messages
Passay provides the MessageResolver
interface to allow arbitrary
conversion of password validation results to meaningful text intended for display to users. The default mechanism
uses a message bundle to define validation messages whose default values are shown below.
HISTORY_VIOLATION=Password matches one of %1$s previous passwords.
ILLEGAL_WORD=Password contains the dictionary word '%1$s'.
ILLEGAL_WORD_REVERSED=Password contains the reversed dictionary word '%1$s'.
ILLEGAL_DIGEST_WORD=Password contains a dictionary word.
ILLEGAL_DIGEST_WORD_REVERSED=Password contains a reversed dictionary word.
ILLEGAL_MATCH=Password matches the illegal pattern '%1$s'.
ALLOWED_MATCH=Password must match pattern '%1$s'.
ILLEGAL_CHAR=Password %2$s the illegal character '%1$s'.
ALLOWED_CHAR=Password %2$s the illegal character '%1$s'.
ILLEGAL_QWERTY_SEQUENCE=Password contains the illegal QWERTY sequence '%1$s'.
ILLEGAL_ALPHABETICAL_SEQUENCE=Password contains the illegal alphabetical sequence '%1$s'.
ILLEGAL_NUMERICAL_SEQUENCE=Password contains the illegal numerical sequence '%1$s'.
ILLEGAL_USERNAME=Password %2$s the user id '%1$s'.
ILLEGAL_USERNAME_REVERSED=Password %2$s the user id '%1$s' in reverse.
ILLEGAL_WHITESPACE=Password %2$s a whitespace character.
ILLEGAL_NUMBER_RANGE=Password %2$s the number '%1$s'.
ILLEGAL_REPEATED_CHARS=Password contains %3$s sequences of %1$s or more repeated characters, but only %2$s allowed: %4$s.
INSUFFICIENT_UPPERCASE=Password must contain %1$s or more uppercase characters.
INSUFFICIENT_LOWERCASE=Password must contain %1$s or more lowercase characters.
INSUFFICIENT_ALPHABETICAL=Password must contain %1$s or more alphabetical characters.
INSUFFICIENT_DIGIT=Password must contain %1$s or more digit characters.
INSUFFICIENT_SPECIAL=Password must contain %1$s or more special characters.
INSUFFICIENT_CHARACTERISTICS=Password matches %1$s of %3$s character rules, but %2$s are required.
INSUFFICIENT_COMPLEXITY=Password meets %2$s complexity rules, but %3$s are required.
INSUFFICIENT_COMPLEXITY_RULES=No rules have been configured for a password of length %1$s.
SOURCE_VIOLATION=Password cannot be the same as your %1$s password.
TOO_LONG=Password must be no more than %2$s characters in length.
TOO_SHORT=Password must be %1$s or more characters in length.
TOO_MANY_OCCURRENCES=Password contains %2$s occurrences of the character '%1$s', but at most %3$s are allowed.
The following example demonstrates how to replace the default message bundle with a custom/localized properties file.
Advanced validation: M of N rules
Many password policies contain a rule of the form password must contain at least M of the following N categories.
The CharacterCharacteristicsRule
component supports
this use case. Consider the following policy:
- Length of 8 to 16 characters
- Must contain characters from at least 3 of the following: upper, lower, digit, symbol
- No whitespace characters
This policy is implemented in the following code excerpt.
Advanced validation: dictionary rules
Many password policies seek to prevent common words (e.g. password) from appearing in passwords. Passay ships with two rules that can be used with arbitrary word lists to enforce dictionary policies:
DictionaryRule
- exact matching semanticsDictionarySubstringRule
- contains matching semantics
DictionarySubstringRule
should be used judiciously since a configuration with a sizeable common word list would
prevent strong passwords like correcthorsebatterystaple and random.words@31415.
A reasonable use case might be a relatively short list of reserved words forbidden to appear in passwords.
DictionaryRule
, on the other hand, has a valuable common use case: preventing known weak passwords.
Configuring this rule with a published list of popular passwords, such as those from the
Adobe breach, can dramatically increase password security by
preventing common, and therefore insecure, passwords.
Provided dictionaries
JDBCDictionary
- searches for words in a databaseWordListDictionary
- searches for words in a list of StringsArrayWordList
- an in-memory list of wordsFileWordList
- a file backed list of words (best for smaller file sizes)MemoryMappedFileWordList
- a file backed list of words that leverages aMappedByteBuffer
(best for larger file sizes)
BloomFilterDictionary
- searches for words in a Bloom Filter- Uses the
BloomFilter
implementation provided in the Google Guava library. Note that bloom filters by nature report false positives, be sure to construct a filter with a thoughtful false positive probability.
- Uses the
TernaryTreeDictionary
- searches for words in an in-memory tree structure
Advanced validation: password history
The following rules support enforcement of unique passwords in the context of password history:
HistoryRule
- for passwords stored as cleartext (insecure, uncommon)DigestHistoryRule
- for passwords stored as a hash/digest
Both rules require querying a data source for historical password data, but in practice DigestHistoryRule
is the more useful component since passwords are typically stored as a hash/digest. Digest support requires the use of message digest components provided by the cryptacular crypto library, which is an optional dependency of this library. The example below demonstrates history-based validation for passwords stored in the following format:
- SHA-256 digest algorithm
- The hash is computed by digesting two values in turn:
- Password string as UTF-8 characters
- Random 16-byte salt value
- The salt is appended to the hash output to form a 48-byte value (32-byte hash + 16-byte salt)
- The hash output is encoded as base64 characters
This is a realistic scenario for passwords stored in an LDAP directory using the SSHA pseudo-standard.
Password generation
The password generation API uses a specialized ruleset consisting exclusively of CharacterRule
, a specialization of
Rule
, to define the requisite character classes in generated passwords. The example below demonstrates
password generation for the following policy:
- Length of 8 to 16 characters
- Must contain at least one of the following: upper case, lower case and digit
- No whitespace characters
Note that generated passwords in the above example don’t contain spaces since none of the character sets above
includes a space character. It is trivial to add support for generating passwords with spaces by including an
additional CharacterRule
with a custom character set as follows.