This is a short tutorial to get you started with Password Rodeo.
Introduction
The two main classes in Password Rodeo are
PasswordMaker
and
PasswordChecker
.
The first one allows you to generate random passwords according to a set of criteria you specify. The second one allows you to validate passwords submitted by your users, again according to a set of criteria that you get to specify.
We’ll examine first how to check passwords submitted by the users of your application and then how to generate random passwords.
Validating Passwords with PasswordChecker
Let’s assume we need the users of our application to create a password before they can log in. Let’s also assume that we would like this password to be minimally secure, and therefore we’ll require their password to be at least 8 characters long and contain at least one lower-case letter, one upper-case letter and one digit.
Let’s create a PasswordChecker
to do just that:
var checker = PasswordChecker.factory()
.setMinMaxLength(8, 16)
.addCharGroup(CharacterGroups.LOWER_CASE, 1)
.addCharGroup(CharacterGroups.UPPER_CASE, 1)
.addCharGroup(CharacterGroups.DIGITS, 1)
.create();
The second argument of setMinMaxCharCount specifies the maximum length of the password. This argument
is mandatory and should be set to a value between 2 and 5 times the minimum length. (Unlimited password
lengths can lead to security issues. Feel free to research the subject on the internet.)
|
The first argument to addCharGroup is a String that contains characters allowed in the password
(for exemple "abcdefgh" ). The
CharacterGroups
class contains a few pre-defined character lists to get you started.
|
To check if a password matches the validation criteria, you can use one of three functions provided
by PasswordChecker
: quickCheck
, check
or fullCheck
.
If you need a simple yes or no answer, use quickCheck
:
assert checker.quickCheck("Abcdef12") == true;
assert checker.quickCheck("Abcdef1") == false; // too short
assert checker.quickCheck("Abcdefgh") == false; // no digit
assert checker.quickCheck("@bcdef12") == false; // illegal character
If you need to know why a password is rejected, use the check
function:
assert checker.check("Abcdef12").equals(PasswordCheckStatus.OK);
assert checker.check("Abcdef1").equals(PasswordCheckStatus.TOO_SHORT);
assert checker.check("Abcdefgh").equals(PasswordCheckStatus.NOT_ENOUGH_OF_CHARACTER_GROUP); // no digit
assert checker.check("@bcdef12").equals(PasswordCheckStatus.ILLEGAL_CHARACTER);
The check
function return a value from the enum
PasswordCheckStatus
that either indicates that the password is OK
, or the first error condition encountered that you can then
report to the user.
As mentioned only the first error detected is returned by this method. If you need a full report, you need to use
the fullCheck
method. This method returns a List
of
PasswordCheckError
s.
The List
is empty if there is no error, otherwise it’s possible to iterate over the List
to process each error.
If the error is of type ILLEGAL_CHARACTER
, the PasswordCheckError
in the list is actually a subclass,
IllegalCharacterError
,
on which the method getIllegalCharacter
can be called to identify the illegal character.
If the error is of type NOT_ENOUGH_OF_CHARACTER_TYPE
or TOO_MANY_OF_CHARACTER_TYPE
, the PasswordCheckError
in the
list will be of the
BadCountForCharacterTypeError
subclass, which contains methods to identify the character list concerned and further details regarding the bad
character counts.
Here is an exemple:
List<PasswordCheckError> errors = checker.fullCheck("Ab$@");
PasswordCheckError tooShort = errors.get(0);
assert tooShort.getErrorType().equals(PasswordCheckStatus.TOO_SHORT);
assert errors.get(1).getErrorType().equals(PasswordCheckStatus.ILLEGAL_CHARACTER);
IllegalCharacterError illegalChar1 = (IllegalCharacterError) errors.get(1);
assert illegalChar1.getIllegalCharacter().equals("$");
assert errors.get(2).getErrorType().equals(PasswordCheckStatus.ILLEGAL_CHARACTER);
IllegalCharacterError illegalChar2 = (IllegalCharacterError) errors.get(2);
assert illegalChar2.getIllegalCharacter().equals("@");
assert errors.get(3).getErrorType().equals(PasswordCheckStatus.NOT_ENOUGH_OF_CHARACTER_GROUP);
BadCountForCharacterTypeError missingCharType = (BadCountForCharacterTypeError) errors.get(3);
assert missingCharType.getCharacterGroup().equals(CharacterGroups.DIGITS);
assert missingCharType.getExpectedCount() == 1;
assert missingCharType.getActualCount() == 0;
As you can see there are 4 problems with this password that all get reported in detail:
-
the password is too short (error 0);
-
the character
$
is not allowed (error 1); -
the character
@
is not allowed (error 2); -
the password doesn’t contain any digit (error 3).
For a more thorough presentation of password validation, and the fullCheck method in particular,
please refer to the
full Manual.
|
Two more configuration examples
Before tackling password generation, let’s look at two more examples.
Let’s assume, we would like to impose more stringent constraints on user passwords and decide that our passwords
should have a minimum length of 16 characters and a maximum length of 64 characters. Furthermore, we want
the passwords to be composed of a mix of upper-case and lower-case letters and digits with at least one of each
type of characters present. We would also like to allow the user to use symbols in their password (like $
, &
,
*
, etc.)
Here is how to do it:
var checker = PasswordChecker.factory()
.setMinMaxLength(16, 64)
.addCharGroup(CharacterGroups.LOWER_CASE, 1)
.addCharGroup(CharacterGroups.UPPER_CASE, 1)
.addCharGroup(CharacterGroups.DIGITS, 1)
.addCharGroup(CharacterGroups.SYMBOLS)
.create();
The PasswordChecker class uses an
internal factory class
to initialize its instances.
|
Here is a more extreme example: the password needs to be at least 32 characters long and no more than 160; it has to be composed of upper and lower-case characters, digits and symbols. At least one of each type of characters must be present. Also, we don’t want more than 5 digits or 3 symbols.
Here is the code to implement this:
var checker = PasswordChecker.factory()
.setMinMaxLength(32, 160)
.addCharGroup(CharacterGroups.LOWER_CASE, 1)
.addCharGroup(CharacterGroups.UPPER_CASE, 1)
.addCharGroup(CharacterGroups.DIGITS, 1, 5)
.addCharGroup(CharacterGroups.SYMBOLS, 1, 3)
.create();
This is just a weird example. Please be reasonable with the constraints you place on your users' passwords. |
Creating Passwords with PasswordMaker
Let’s go back to our first example of a minimally secure password, containing between 8 and 16 characters, with upper-case and lower-case characters and digits (with at least one character in each of these categories).
To generate these kinds of passwords, you would use:
var maker = PasswordMaker.factory()
.setLength(12)
.addCharGroup(CharacterGroups.LOWER_CASE, 1)
.addCharGroup(CharacterGroups.UPPER_CASE, 1)
.addCharGroup(CharacterGroups.DIGITS, 1)
.create();
You can then call maker.create()
to generate 12 characters long passwords that comply with the criteria
specified above.
Let’s build something a little more secure:
-
32 characters long;
-
at least one upper-case and one lower-case character;
-
between 1 and 3 digits;
-
2 symbols;
-
and also we want to avoid similar characters that could confuse the user (like
1
vs.I
vs.l
, or0
vs.o
vs.O
).
var maker = PasswordMaker.factory()
.setLength(12)
.addCharGroup(CharacterGroups.UNAMBIGUOUS_LOWER_CASE, 1)
.addCharGroup(CharacterGroups.UNAMBIGUOUS_UPPER_CASE, 1)
.addCharGroup(CharacterGroups.UNAMBIGUOUS_DIGITS, 1, 3)
.addCharGroup(CharacterGroups.UNAMBIGUOUS_SYMBOLS, 2, 2)
.create();
CharacterGroups
contains list of unambiguous characters you can use to help your users. It’s best to avoid these characters
if your users will need to type their password in, especially on a mobile device.
|
Another example: let’s say we need to generate a random 20 hexadecimal digits string:
var maker = PasswordMaker.factory()
.setLength(20)
.addCharGroup("0123456789ABCDEF")
.create();
What if you need a random string of characters and numbers to be part of a user-specific URL (password reset link for example). How about:
var maker = PasswordMaker.factory()
.setLength(64)
.addCharGroup(CharacterGroups.LOWER_CASE)
.addCharGroup(CharacterGroups.UPPER_CASE)
.addCharGroup(CharacterGroups.DIGITS)
.create();
You can use PasswordMaker in many situations that requires the creation of a random string of
characters according to a predefined pattern.
|
Internally PasswordMaker uses ThreadLocalRandom.current() to generate random numbers for
password creation. You can specify your own source of random numbers if you need to. Please refer
to the full Manual for this.
|
Conclusion
I hope that this short tutorial gave you all the information needed to get started with Password Rodeo. For more information, please refer to the Password Rodeo Manual or the Javadoc.