Easy.Password.Validator
1.2.4
dotnet add package Easy.Password.Validator --version 1.2.4
NuGet\Install-Package Easy.Password.Validator -Version 1.2.4
<PackageReference Include="Easy.Password.Validator" Version="1.2.4" />
paket add Easy.Password.Validator --version 1.2.4
#r "nuget: Easy.Password.Validator, 1.2.4"
// Install Easy.Password.Validator as a Cake Addin #addin nuget:?package=Easy.Password.Validator&version=1.2.4 // Install Easy.Password.Validator as a Cake Tool #tool nuget:?package=Easy.Password.Validator&version=1.2.4
Easy Password Validator
This project was created to provide an easy to use and configurable password validation library. If the default configuration is sufficient for your needs the library can be used out of the box without further setup. However, if you have specific validation needs you can alter the library configuration settings and also provide custom validation methods.
There are two parts to this library: score checking and validation testing. Testing a password will perform both actions. The score checking will provide an overall score to a password which is the sum of all test scores. The validation testing will return whether a password passed or failed the tests.
The default implementation will check for the following:
- Contains digits
- Contains uppercase letters
- Contains lowercase letters
- Contains punctuation marks or symbols
- Checks password length
- Checks number of unique characters
- Checks for QWERTY, QWERTZ, or AZERTY keyboard patterns (ex. asDFr$)
- Checks for repeat characters (ex. tttttt)
- Checks password entropy (disabled by default)
- Checks if password is in top 100,000 bad password list
- Checks if decoded l33t versions of password are in top 10,000 bad password list
These checks will result in a pass or fail value being returned based on the provided password requirements. The score is not altered by the requirements.
Breaking Changes V1.2
Notice!
When upgrading to version 1.2 or higher please check that the following are ready for the upgrade. Most likely you will be fine, but there are some specific cases that could cause problems.
IPasswordRequirements
has new properties, if you are using a custom implementation you will need to add these- Setting
IPasswordRequirements.MaxNeighboringCharacter
to 0 no longer disables theTestPattern
test; setIPasswordRequirements.UsePattern
to false for this - Setting
IPasswordRequirements.MaxRepeatSameCharacter
to 0 no longer disables theTestRepeat
test; setIPasswordRequirements.UseRepeat
to false for this - Setting
IPasswordRequirements.MinEntropy
to 0 no longer disables theTestEntropy
test and is considered invalid
Getting Started
These instuctions can be used to acquire and implement the library.
Installation
To use this library either clone a copy of the repository or check out the NuGet package
Usage
Basic Example
The following example provides a complete use case. This example makes use of the most basic configuration.
Console.WriteLine("Enter a username:");
var username = Console.ReadLine();
Console.WriteLine("Enter a password to test:");
var password = Console.ReadLine();
var passwordValidator = new PasswordValidatorService(new PasswordRequirements());
var pass = passwordValidator.TestAndScore(password, new string[] { username });
if (pass)
Console.WriteLine($"Password passed validation with score: {passwordValidator.Score}");
else
Console.WriteLine($"Password failed validation with score: {passwordValidator.Score}");
if (pass == false)
foreach (var message in passwordValidator.FailureMessages)
Console.WriteLine(message);
Usage as a service in Web API
The following example displays how to register the PasswordValidatorService
as an injectable service.
Modify Startup.cs as follows:
public void ConfigureServices(IServiceCollection services) {
// Your other startup items
// Register password validator
services.AddTransient(service => new PasswordValidatorService(new PasswordRequirements()));
}
Once that has been done you can simply pull a copy into your controllers as follows:
public class MyCustomController : ControllerBase {
private readonly PasswordValidatorService PasswordValidator;
public MyCustomController(PasswordValidatorService passwordValidatorService) {
PasswordValidator = passwordValidatorService;
}
}
Usage in Blazor WebAssembly
Since Blazor WebAssembly is not able to use asynchronous code in a synchronous manner, an extra step is required if use of the bad lists is desired. Note the call to .Initialize()
, this will perform the bad list loading with the await
keyword.
Console.WriteLine("Enter a password to test:");
var password = Console.ReadLine();
var passwordValidator = new PasswordValidatorService(new PasswordRequirements());
await passwordValidator.Initialize();
var pass = passwordValidator.TestAndScore(password);
if (pass)
Console.WriteLine($"Password passed validation with score: {passwordValidator.Score}");
else
Console.WriteLine($"Password failed validation with score: {passwordValidator.Score}");
Using custom configuration
In the previous example, the call to new PasswordRequirements()
was done inline in the service setup. However, it can be prepared beforehand and the validator will use different settings or you can create your own using IPasswordRequirements
.
var requirements = new PasswordRequirements()
{
MinLength = 4,
ExitOnFailure = true,
RequireDigit = true,
MinScore = 50,
UseEntropy = true,
UseDigit = false
};
var passwordValidator = new PasswordValidatorService(requirements);
Note that disabling a test with a property such as IPasswordRequirements.UseDigit
will prevent that test from failing and also will not provide any score modification. For that reason the recommended action is to leave the enablement settings as is.
Adding A Custom Tester
The system also supports adding your own password tests that will run with the built-in ones. This is done by using IPasswordTest
.
The sample tester class.
private class TestWhiteSpace : IPasswordTest
{
public int ScoreModifier { get; set; }
public string FailureMessage { get; set; }
public IPasswordRequirements Settings { get; set; }
public bool TestAndScore(string password)
{
// Reset
FailureMessage = null;
ScoreModifier = 0;
// Check for digits
var whitespace = password.Count(char.IsWhiteSpace);
// Adjust score
ScoreModifier = whitespace * 2;
// Return result
var pass = whitespace > 0;
if (pass == false)
FailureMessage = "Must have at least one space in password";
return pass;
}
}
Adding to validator service.
var passwordValidator = new PasswordValidatorService(new PasswordRequirements());
passwordValidator.AddTest(new TestWhiteSpace());
Adding A Custom Pattern
The pattern matcher checks for QWERTY keyboard patterns by default. You may add another instance of the pattern matcher with your own custom patterns (for example alphabetical order checking).
var requirements = new PasswordRequirements();
var passwordValidator = new PasswordValidatorService(requirements);
var pattern = new List<PatternMapItem>()
{
new PatternMapItem() { RegularKey = 'a', ShiftKey = 'A', NeighborKeys = new char[] { 'b', 'B' } },
new PatternMapItem() { RegularKey = 'b', ShiftKey = 'B', NeighborKeys = new char[] { 'a', 'A', 'c', 'C' } },
new PatternMapItem() { RegularKey = 'c', ShiftKey = 'C', NeighborKeys = new char[] { 'b', 'B', 'd', 'D' } },
new PatternMapItem() { RegularKey = 'd', ShiftKey = 'D', NeighborKeys = new char[] { 'c', 'C', 'e', 'E' } } // And so on
};
var test = new TestPattern(requirements, pattern);
passwordValidator.AddTest(test);
You can change the default instance of TestPattern to run its test based on QWERTZ, AZERTY, or custom layouts as well. To do so set the IPasswordRequirements.KeyboardStyle
to the desired value. If you select custom you must provide your list as a parameter in the constructor for PasswordValidatorService
.
Using A Custom L33T Dictionary
If desired, a custom L33T decoding dictionary may be used, or you may extend or modify the built in dictionary.
var passwordValidator = new PasswordValidatorService(new PasswordRequirements());
var l33TReplacements = L33tDecoderService.GetReplacements(L33tLevel.Advanced).ToList();
l33TReplacements.Add(new L33tReplacement() { PlainText = "h", L33tEncoded = "|~|", RunOrder = 15 });
l33TReplacements.Add(new L33tReplacement() { PlainText = "h", L33tEncoded = "]~[", RunOrder = 15 });
passwordValidator.UpdateL33tReplacements(l33TReplacements);
The run order for l33t replacements has been laid out as follows, and you may select any run order for your custom replacements.
- 10
L33tLevel.Advanced
, not contained in any other replacements - 20
L33tLevel.Advanced
, contained in another replacement at RunOrder 10 - 30
L33tLevel.Advanced
, contained in at least one other replacement at RunOrder 10 or 20 - 40
L33tLevel.Intermediate
, not contained in any other replacements - 50
L33tLevel.Intermediate
, contained in at least one other replacement at RunOrder 10 or 40 - 60
L33tLevel.Intermediate
, contained in at least one other replacement at RunOrder 10, 20, 40, or 50 - 70
L33tLevel.Basic
, not contained in any other replacements - 80
L33tLevel.Basic
, contained in at least one other replacement at RunOrder 10, 40, or 70 - 90
L33tLevel.Basic
, contained in at least one other replacement at RunOrder 10, 20, 40, 50, 70, or 80
Using error messages in another language
Error messages are provided using .RESX files and are currently available in the following languages:
- English (en, en-CA, en-US)
- French (fr)
- German (de)
- Italian (it)
- Romanian (ro)
By default error messages will be returned based on the language of the operating system (defaults to English if specified language is not available). To choose a specific language enter the language code in the .TestAndScore()
method. Language codes are either 2 or 5 characters in length (ex. en, en-US, de, de-DE).
Console.WriteLine("Enter a username:");
var username = Console.ReadLine();
Console.WriteLine("Enter a password to test:");
var password = Console.ReadLine();
var passwordValidator = new PasswordValidatorService(new PasswordRequirements());
var pass = passwordValidator.TestAndScore(password, new string[] { username }, "de");
To add another language you must use the Git repository, the NuGet package does not support adding languages. To do so add a .RESX file with the proper language code and update the .CheckValidLanguage()
method in PasswordValidatorService.cs
. To simplify the creation of the .RESX files you can use Zeta Resource Editor with the .zeproj file included in the repository.
If you do add support for a language that is not bundled here, please let me know or fork the repository so I can update the master branch and NuGet package. Looking for high-quality translations only, i.e. no copy paste from translation services.
Authors
- NF Software Inc.
License
This project is licensed under the MIT License - see the LICENSE file for details
Acknowledgments
Parts of this library have been inspired by:
Thank you to:
- Daniel Miessler for the SecLists project
- Kmg Design for the project icon
- Uwe Keim for help with translation system and German translation
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.2.4 | 9,702 | 5/18/2024 |
1.2.3 | 2,767 | 3/21/2024 |
1.2.2 | 224 | 3/18/2024 |
1.1.8 | 16,263 | 8/24/2023 |
1.1.7 | 729 | 8/16/2023 |
1.1.6 | 812 | 8/1/2023 |
1.1.5 | 885 | 7/24/2023 |
1.1.4 | 13,088 | 2/8/2023 |
1.1.3 | 6,434 | 1/2/2023 |
1.1.2 | 1,286 | 9/14/2022 |
1.1.1 | 5,507 | 12/29/2020 |
1.1.0 | 1,173 | 11/10/2020 |
1.0.4 | 1,233 | 11/3/2020 |
1.0.3 | 1,273 | 8/13/2020 |
1.0.2 | 1,186 | 5/7/2020 |
1.2.4
Add Polish translation for error messages
1.2.3
Update publishing to include source link, deterministic, and compiler flags
1.2.2
Bugfix for TestBadList exception
1.2.1
Add number pad layout and Include symbols in punctuation test
1.2.0
Add support for alternate keyboard layouts and Per test enablement settings
1.1.8
Add method to load bad lists in Blazor WebAssembly; add support for French, Italian, and Romanian error messages
1.1.7
Bugfix for running in Blazor WebAssembly, improve bad list loading
1.1.6
Add support for custom bad lists, add support for custom bad list locations, and improve error checking
1.1.5
Update project file to generate XML documentation in NuGet package
1.1.4
Add resource file for en-CA spellings
1.1.3
Add support for .NET Standard 2.0
1.1.2
Update output DLL name
1.1.1
Add entropy tester
1.1.0
Add support for error messages in other languages (German included in this update)
1.0.4
Add XML file to output to allow Intellisense to work with package
1.0.3
Add ability to run when loading bad lists fails
1.0.2
Add remote download of bad lists for NuGet package
1.0.1
Fix issue caused by dependent text files not being available in NuGet package