Password Rodeo is a small library used to validate and create passwords. This is the programmer manual for its use.
Introduction
Password Rodeo allows you to create and/or validate passwords according to certain specified criteria (length, character composition, etc.)
The applications of the library are not limited to passwords. It can be used to create/validate any type of string made up of random characters. Examples would be long strings included in URLs for sensitive administrative links, database ID fields, PIN codes, etc.
The library supports all Unicode characters and should work reliably even with characters encoded on more than two bytes.
Password Rodeo requires at least Java 11, but adapting its source code to an older version of Java should be fairly simple if you are so inclined. It’s open source and distributed under the Apache Licence 2.0. The source code can be found on GitHub.
The two main classes in Password Rodeo are
PasswordChecker
for password validation and
PasswordMaker
for password generation. Their use is described in the sections below.
If you would like to quickly get up to speed, I would recommend consulting the Password Rodeo Tutorial. Class details can be found in the project Javadoc.
Installation
You can get the library from the Download Page or use your favorite dependency management system to obtain it from Maven Central.
Validating Passwords
To validate passwords, you create a
PasswordChecker
object with the required parameters. You can then use any of three different methods to validate passwords.
Internal Factory
To facilitate setup, PasswordChecker
uses an internal Factory,
PasswordChecker.Factory
,
that implements a
fluent interface.
Here is the minimum code to implement a PasswordChecker
:
PasswordChecker checker = PasswordChecker.factory()
.addCharGroup("abcdefgh")
.create();
This creates a PasswordChecker
that’ll validate passwords composed of the following characters: abcdefgh
, with
a length between 16 and 32 characters.
At least one character group must be specified. The other parameters have default values. How to alter these parameters is described in the sections below.
Password Length
To alter the allowed password length, use the function
setMinMaxLength(int minLength, int maxLength)
which takes the minimum and maximum length of the password as parameters.
The minimum length is 1. Minimum and maximum length can be identical. The default values are 16 for the minimum length and 32 for the maximum.
Example:
factory.setMinMaxLength(32, 96); // min length = 32, max length = 96
Character Group Constraints
A password is composed of characters. At least one character group must be provided as the source of the password characters.
It is possible to specify an unlimited number of groups (but 3 to 5 is the norm) with added constraints on the minimum and maximum number of character from each group that need to be present in the password.
Examples of character groups would be: all lower-case alphabetical characters, all upper-case alphabetical characters, digits from 0 to 9, etc.
To specify a group, use one of the following variants of the addCharGroup
function:
Where:
-
charGroup
is the group of characters to be used; by default there should be no duplicate in the list or anIllegalStateException
will be thrown (see Duplicate characters below for more information); -
minCount
is the minimum number of characters from this group that should be present in the password; the default value is zero; (also, the value should not be negative and should be smaller or equal tomaxCount
); -
maxCount
is the maximum number of characters from this group that should be present in the password; the value 0 (zero), which is also the default, means no upper limit. (Also, the value should not be negative, and if different from zero should be greater than or equal tominCount
.)
Here are a few examples:
factory.addCharGroup("abcdef"); // no min or max count
factory.addCharGroup("xyzuvw", 1); // at least one character from group, no max
factory.addCharGroup("0123456789", 2, 5); // 2 chars from group but no more than 5
Duplicate characters
By default, duplicate characters are not allowed in a PasswordChecker
. To be more precise:
-
a character group cannot contain the same character twice or more times;
-
a character group cannot contain a character that is already present in a different character group.
If one of the two conditions above is violated, the addCharGroup
function will throw an IllegalArgumentException
.
If you wish for duplicate characters to be allowed in your PasswordChecker
, you should call the
disallowDuplicateCharacters
method on your factory with an argument of false
:
factory.disallowDuplicateCharacters(false);
disallowDuplicateCharacters
must be called before you start adding character groups that contains duplicates.
Duplicate characters in the same character group do not serve any purpose as far as password validation
is concerned. Duplicate characters across two or more character groups can have a deep impact on password
validation and should not be used unless you know what you’re doing; typically, you would be mirroring a
similar setup in a PasswordMaker context. See Duplicate Characters in Password Generation for more
information.
|
Pre-defined Character Groups
To help in the creation of standard PasswordChecker
and PasswordMaker
, the utility class
CharacterGroups
contains a few typical character groups:
Character Group | Content |
---|---|
LOWER_CASE |
abcdefghijklmnopqrstuvwxyz |
UPPER_CASE |
ABCDEFGHIJKLMNOPQRSTUVWXYZ |
DIGITS |
0123456789 |
SYMBOLS |
!@#$%&*-_=+|?{}[]()/'",.;:<> |
UNAMBIGUOUS_LOWER_CASE |
abcdefghijkmnpqrstuvwxyz |
UNAMBIGUOUS_UPPER_CASE |
ACDEFGHJKLMNPQRSTUVWXYZ |
UNAMBIGUOUS_DIGITS |
2345679 |
UNAMBIGUOUS_SYMBOLS |
!@#$%&*-_=+|? |
The UNAMBIGUOUS
variations can be used to avoid confusion when users have to type their password, especially
on a mobile device. (They are more useful in PasswordMaker
than PasswordChecker
.)
Creating the PasswordChecker
Once you have set all the parameters, you can create your PasswordChecker
:
PasswordChecker checker = factory.create();
Or for a full exemple:
PasswordChecker checker = PasswordChecker.factory()
.setMinMaxLength(32, 96)
.addCharGroup(CharacterGroups.LOWER_CASE, 1)
.addCharGroup(CharacterGroups.UPPER_CASE, 1)
.addCharGroup(CharacterGroups.DIGITS, 1, 2)
.addCharGroup(CharacterGroups.SYMBOLS, 0, 3)
.create();
Password Validation
Once a PasswordChecker
has been set up, it can be used to validate passwords. There are three functions
available:
-
quickCheck(String password)
: returns a boolean,true
if the password is valid,false
otherwise; -
check(String password)
: returns anenum
value describing the status of the validated password (eitherOK
or the first error condition encountered); -
fullCheck(String password)
: returns a list of errors encountered while analysing the password (the list is empty if the password is ok).
The following three sections describe each function in detail.
quickCheck()
The
quickCheck
function returns true
if the password can be validated or false
otherwise.
This function should be used to perform quick validation when there is no need to report the exact problem encountered if it fails.
Typically, you’ll want to give some feedback to the user as to why the password they selected got rejected and therefore use one of the other two functions available.
check()
The
check
function returns an enum
of type
PasswordCheckStatus
to indicate the result of the validation process.
Possible value returned are:
Value | Description |
---|---|
|
The password was successfully validated. All criteria are met. |
|
The password is too short, below the minimum length specified. |
|
The password is too long, above the maximum length specified. |
|
The password contains one or more illegal characters, i.e., characters not present in any character group |
|
The password does not contain enough characters from a certain group (for example, a digit is required and there is none in the password submitted) |
|
The password contains too many characters from a certain group (for example, a maximum of 3 symbols is allowed but 4 or more were found) |
This function reports only the first error encountered, although there might be more than one problem with the password. Error conditions are checked for in the order listed in the above table. |
fullCheck()
The
fullCheck
function returns a List
of
PasswordCheckError
objects, each one detailing a different problem found with the password. If there are no problems, the List
will
be empty.
You can call the function getErrorType()
on a PasswordCheckError
object to identify the problem:
the return value is an element from the enum
PasswordCheckStatus
(see table in section check())
for possible values.
In some cases, the object in the list is of a subclass of PasswordCheckError
:
-
IllegalCharacterError
, if the password contains a character that is not allowed in any character group (ILLEGAL_CHARACTER
error); -
BadCountForCharacterTypeError
, if the password contains not enough or too many characters of a certain group (NOT_ENOUGH_OF_CHARACTER_GROUP
orTOO_MANY_OF_CHARACTER_GROUP
error).
In the first case, IllegalCharacterError
offers two functions to retrieve the offending character:
-
getIllegalCharacter()
will return the offending character as aString
; -
getIllegalCodePoint()
will return the offending character as a code point (int
).
In the second case BadCountForCharacterTypeError
make the following information available:
Function | Description |
---|---|
If the error is of type |
|
Returns how many characters are actually present. |
|
Returns the character group affected by the problem as a |
|
Returns the index of the character group. The index of character groups is determined by the order in which
they were specified via one of the |
Creating Passwords
To create passwords, you create a
PasswordMaker
object with the required parameters.
Once this is done, you can call the
create
fonction as required to create passwords.
Internal Factory
To facilitate setup, PasswordMaker
uses an internal Factory,
PasswordMaker.Factory
,
that implements a
fluent interface.
Here is the minimum code to implement a PasswordMaker
:
PasswordMaker maker = PasswordMaker.factory()
.addCharGroup("abcdefgh")
.create();
This creates a PasswordMaker
that will generate passwords composed of the characters abcdefgh
with
a length of 16 characters.
At least one character set must be specified. The other parameters have default values. How to alter these parameters is described in the sections below.
Password Length
To alter the created password length, use the function
setLength(int length)
which takes the generated password length as parameter.
The minimum length is 1. The default value is 16.
Example:
factory.setLength(32); // password length = 32
Character Set Constraints
A password is composed of characters. At least one character group must be provided as a source of password characters.
It is possible to specify an unlimited number of groups (but 3 to 5 is the norm) with added constraints on the minimum and maximum number of characters from each group that need to be present in the password.
Examples of character groups would be: all lower-case alphabetical characters, all upper-case alphabetical characters, digits from 0 to 9, etc.
To specify a group, use one of the following variants of the addCharGroup
function:
Where:
-
charGroup
is the group of characters to be used; by default there should be no duplicate in the list or anIllegalStateException
will be thrown (see Duplicate Characters in Password Generation below for more information); -
minCount
is the minimum number of characters from this group that should be present in the password; the default value is zero; (also, the value should not be negative and should be smaller or equal tomaxCount
); -
maxCount
is the maximum number of characters from this group that should be present in the password; the value 0 (zero), which is also the default, means no upper limit. (Also, the value should not be negative, and if different from zero should be greater than or equal tominCount
.)
Here are a few examples:
factory.addCharGroup("abcdef"); // no min or max count
factory.addCharGroup("xyzuvw", 1); // at least one character from group, no max
factory.addCharGroup("0123456789", 2, 5); // 2 chars from group but no more than 5
Duplicate Characters in Password Generation
By default, duplicate characters are not allowed in a PasswordMaker
. To be more precise:
-
a character group cannot contain the same character twice or more times;
-
a character group cannot contain a character that is already present in a different character group.
If one of the two condition above is violated, the addCharGroup
function will throw an IllegalArgumentException
.
If you wish for duplicate characters to be allowed in your PasswordMaker
, you should call the
disallowDuplicateCharacters
method on your factory with an argument of false
:
factory.disallowDuplicateCharacters(false);
disallowDuplicateCharacters
must be called before you start adding character groups that contains duplicates.
Duplicating characters in the composition of your password is of dubious value. If you want to obtain
a specific composition in terms of characters from certain groups, you should use function addCharGroup
parameters to specify minimum and maximum character counts.
|
Pre-defined Character Groups in Password Generation
To help in the creation of standard PasswordChecker
and PasswordMaker
, the utility class
CharacterGroups
contains a few typical character groups. Please see Pre-defined Character Groups above for more information.
Generating Random Numbers
Generating random passwords is an application of random number generation.
To control the way it’s done, you can pass an object implementing the
RandomUIntGenerator
interface to the factory:
factory.setRandomUIntGenerator(new CustomUIntGenerator());
If you don’t define your own RandomUIntGenerator
, an instance of
DefaultUIntGenerator
is used. Internally DefaultUIntGenerator
uses
java.util.concurrent.ThreadLocalRandom
.
Any class implementing the RandomUIntGenerator
interface must provide two functions:
Function | Description |
---|---|
Must return an |
|
Must return an instance of |
Creating the PasswordMaker
Once you have set all the parameters, you can create your PasswordMaker
:
PasswordMaker passwordMaker = factory.create();
Or for a full exemple:
PasswordMaker passwordMaker = PasswordMaker.factory()
.setLength(32)
.addCharGroup(CharacterGroups.LOWER_CASE, 1)
.addCharGroup(CharacterGroups.UPPER_CASE, 1)
.addCharGroup(CharacterGroups.DIGITS, 1, 2)
.addCharGroup(CharacterGroups.SYMBOLS, 0, 3)
.create();
Generating Passwords
Once a PasswordMaker
has been initialized, just use the create()
function to generate passwords.
Checking Generated Passwords
To check generated passwords you can print a bunch of them and visually check that they match what you expect.
Alternatively, you can use a PasswordChecker
with matching parameters to test the generated passwords:
PasswordChecker passwordChecker = PasswordChecker.factory()
.setMinMaxLength(32, 32)
.addCharGroup(CharacterGroups.LOWER_CASE, 1)
.addCharGroup(CharacterGroups.UPPER_CASE, 1)
.addCharGroup(CharacterGroups.DIGITS, 1, 2)
.addCharGroup(CharacterGroups.SYMBOLS, 0, 3)
.create();
PasswordMaker passwordMaker = PasswordMaker.factory()
.setLength(32)
.addCharGroup(CharacterGroups.LOWER_CASE, 1)
.addCharGroup(CharacterGroups.UPPER_CASE, 1)
.addCharGroup(CharacterGroups.DIGITS, 1, 2)
.addCharGroup(CharacterGroups.SYMBOLS, 0, 3)
.create();
for (int i = 0; i < 1_000_000; i++)
assert passwordChecker.quickCheck(passwordMaker.create());
The code above should compile and run for a few seconds without error. You can check your setup with similar
code. If you get an error, double-check your parameters for both the PasswordChecker
and PasswordMaker
.
Other Applications
PasswordMaker
can be used to generate any random string of characters (mac-addresses, reinitialization codes,
plate numbers, etc.), not just passwords. See the Password Rodeo Tutorial for some
examples.