PassphraseRegex: building passphrase validation patterns

Ahmad Mageed edited this page Mar 10, 2014 · 5 revisions

About

The PassphraseRegex class helps construct patterns for passphrase validation. Using a fluent API, a variety of common rules can be applied to produce a pattern that can be used to validate input. The regex produced is generic enough that it can be used on the back-end, or on the front-end via JavaScript.

What makes a strong password?

Good question! Password length strengthens passwords more than some complex criteria. Check out the explanation of the XKCD Password Strength comic to get a better idea.

JavaScript Compatibility

The patterns produced make use of look-aheads, which are supported since JavaScript 1.5, and thus is compatible with modern browsers. That said, people using this library to validate input could make use of a service call that generates the pattern, then apply it dynamically, but that's probably not ideal. Realistically, once the pattern is determined, you could have it passed down when the page is generated, or add it to your JavaScript file (either manually or via some server side JavaScript object assignment).

Demo Site Examples

The demo page shows some example usages along with the ability to exercise some validation patterns.

Similar examples have been added in later sections.

API Details

By default all generated patterns reject leading and trailing whitespace.

Initialization

Initialization is achieved via either of the following 3 properties so that you're free to construct the builder with code that flows nicely with the first method you decided to use:

  • That: e.g. PassphraseRegex.That.IncludesRange(...)
  • Which: e.g. PassphraseRegex.Which.ExcludesCharacters(...)
  • With: e.g. PassphraseRegex.With.MinLength(...)

Methods

  • MinLength(int length): specify the minimum input length (must be >= number of rules used)
  • MaxLength(int length): specify the maximum input length (must be >= number of rules used)
  • IncludesText(string text): require the specified text to exist in the input for it to be considered valid (note: partial matches are used; see examples for clarification)
  • ExcludesText(string text): disallow the specified text from existing in the input for it to be valid
  • IncludesAnyCharacters(string characters): require any (i.e., at least one) of the characters in the string to exist for the input to be valid
  • ExcludesCharacters(string characters): disallow any of the characters in the string for the input to be valid
  • IncludesRange(char start, char end): require any of the characters in the given range, e.g., a-z
  • IncludesRange(int start, int end): same as above; overload to accept integers
  • ExcludesRange(char start, char end): disallow any of the characters in the given range, e.g., 0-9
  • ExcludesRange(int start, int end): same as above; overload to accept integers
  • MaxConsecutiveIdenticalCharacterOf(int length): prevents n identical characters, e.g., a max of 2 would make "aaabc" an invalid match
  • WithMinimumOccurrenceOf(int length): this method is available for some of the positive rules only (i.e., IncludesAnyCharacters and IncludesRange) and specifies the minimum number of characters needed for the input to match
  • Options(RegexOptions options): accepts RegexOptions (useful to ignore case, compile, etc.)
  • ToRegex(): generates the regex pattern based on the specified rules and returns a PassphraseRegexResult class

Exceptions Thrown

Certain methods will throw an exception when given invalid inputs.

  • IncludesText: throws ArgumentException when input is null or empty
  • ExcludesText: same as IncludesText
  • IncludesAnyCharacters: throws ArgumentException when input is null or empty
  • ExcludesCharacters: same behavior as IncludesAnyCharacters
  • IncludesRange (int overload): throws ArgumentOutOfRangeException when inputs are less than 0 or greater than 9.
  • ExcludesRange (int overload): same as IncludesRange
  • WithMinimumOccurrenceOf: throws ArgumentOutOfRangeException when the length is less than 1
  • MaxConsecutiveIdenticalCharacterOf: throws ArgumentOutOfRangeException when the length is less than 2
  • ToRegex: throws ArgumentException if either of the specified min/max lengths are less than the number of rules specified

PassphraseRegexResult Class Properties

Once you've specified the PasspphraseRegex rules and call ToRegex(), a PassphraseRegexResult will be returned with the following properties:

  • IsValid: indicates whether the pattern was successfully generated or not
  • Error: if the pattern was invalid, this contains the Regex class' exception message
  • Pattern: the generated pattern to use with the Regex class
  • Regex: a ready to use Regex class with the generated pattern (null when ToRegex fails)

Examples

General Example

The following code generates a pattern to enforce a password of 8-25 characters that requires at least two lowercase letters in the range of a-z and numbers excluding those in the range of 0-4 (i.e., numbers in the 5-9 range are acceptable).

var builder = PassphraseRegex.With.MinLength(8)
                             .MaxLength(25)
                             .IncludesRange('a', 'z')
                             .WithMinimumOccurrenceOf(2)
                             .ExcludesRange(0, 4);

PassphraseRegexResult result = builder.ToRegex();

if (result.IsValid)
{
    if (result.Regex.IsMatch(input))
        // passphrase meets requirements
    else
       // passphrase is no good
}
else
{
    // check the regex parse exception message for the generated pattern
    Console.WriteLine(result.Error);
}

IncludesAnyCharacters Example

Accept input that contains any of the specified characters (a, b, c, 1, 2, 3).

  • Valid: a, 1, f3
  • Invalid: x, z6, 9

Code:

PassphraseRegex.That.IncludesAnyCharacters("abc123")
                    .ToRegex();

Min/Max and IncludesRange Example

Accept input of length 2-6 that contains any of the characters in the range a-z.

  • Valid: ab, abc123, xyz
  • Invalid: a (too short), AB (case sensitive), 12, !@#, abcdefg (too long)

Code:

PassphraseRegex.With.MinLength(2)
                    .MaxLength(6)
                    .IncludesRange('a', 'z')
                    .ToRegex();

With Minimum Occurrence Constraint

Accept input that contains at least 2 occurrences of characters in the 0-9 range and excludes the characters !, @, #, and characters in the a-z range. The minimum length is set to 3 based on the number of rules specified, which are the Include/Exclude methods (WithMinimumOccurrenceOf isn't counted as a rule since it's a constraint applied to the IncludesRange rule).

  • Valid: 123, 8 % $9-4, A4 B5 (case sensitive)
  • Invalid: 0 (too short), ABC0 (minimum digit occurrence not met), a1b2, 123#

Code:

PassphraseRegex.Which.ExcludesRange('a', 'z')
                     .ExcludesCharacters("!@#")
                     .IncludesRange(0, 9)
                     .WithMinimumOccurrenceOf(2)
                     .ToRegex();

Max Consecutive Identical Character Constraint

Accept input that contains characters in the a-z and 0-9 ranges, with a maximum length of 8 characters, and a maximum of 3 consecutive identical characters. The minimum length is set to 2 based on the number of rules specified, which are the two Include methods (the Max* methods below aren't counted as rules).

  • Valid: a1, abc123, aaa1a (4 'a' characters total, but not more than 3 of them are consecutive)
  • Invalid: abcd12345 (too long), aaaa1 (exceeds max of 3 consecutive identical character constraint), abc (doesn't include any 0-9 characters)

Code:

PassphraseRegex.With.MaxLength(8)
                    .IncludesRange('a', 'z')
                    .IncludesRange('0', '9')
                    .MaxConsecutiveIdenticalCharacterOf(3)
                    .ToRegex();