using DotBased.AspNet.Authority.Managers; using DotBased.AspNet.Authority.Models.Authority; using DotBased.AspNet.Authority.Models.Validation; using DotBased.Extensions; namespace DotBased.AspNet.Authority.Validators; /// /// Validates the password against the options that is configured. /// public class PasswordOptionsValidator : IPasswordValidator { private const string ValidatorId = "Authority.Validator.Password.Options"; private const string ValidationBase = "Authority.Validation.Password"; public async Task ValidatePasswordAsync(AuthorityManager userManager, AuthorityUser user, string password) { if (userManager == null) { throw new ArgumentNullException(nameof(userManager), "User manager is not provided!"); } var passwordOptions = userManager.Options.Password; var errors = new List(); if (password.IsNullOrEmpty() || password.Length < passwordOptions.RequiredLength) { errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.Required.Length", $"Password needs to have a minimum length of {passwordOptions.RequiredLength}")); } if (passwordOptions.RequireDigit && !ContainsDigit(password)) { errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.Required.Digit", "Password must contain a digit!")); } if (passwordOptions.RequireNonAlphanumeric && ContainsNonAlphanumeric(password)) { errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.Required.NonAlphanumeric", "Password must contain a non alphanumeric character.")); } if (passwordOptions.RequireLowercase && password.Any(char.IsLower)) { errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.Required.Lowercase", "Password must contains at least one lowercase character.")); } if (passwordOptions.RequireUppercase && password.Any(char.IsUpper)) { errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.Required.Uppercase", "Password must contains at least one uppercase character.")); } if (passwordOptions.PasswordBlackList.Count != 0 && passwordOptions.PasswordBlackList.Contains(password, passwordOptions.PasswordBlackListComparer)) { errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.Blacklisted", "Given password is not allowed (blacklisted)")); } if (passwordOptions.MinimalUniqueChars > 0 && password.Distinct().Count() < passwordOptions.MinimalUniqueChars) { errors.Add(new ValidationError(ValidatorId, $"{ValidationBase}.UniqueChars", $"Password must contain at least {passwordOptions.MinimalUniqueChars} unique chars.")); } return await Task.FromResult(errors.Count > 0 ? ValidationResult.Failed(errors) : ValidationResult.Ok()); } private bool ContainsDigit(string strVal) => strVal.Any(char.IsDigit); private bool ContainsNonAlphanumeric(string strVal) => !strVal.Any(char.IsLetterOrDigit); }