// Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; namespace Microsoft.AspNet.Identity { /// /// Provides the default password policy for Identity. /// /// The type that represents a user. public class PasswordValidator : IPasswordValidator where TUser : class { /// /// Constructions a new instance of . /// /// The to retrieve error text from. public PasswordValidator(IdentityErrorDescriber errors = null) { Describer = errors ?? new IdentityErrorDescriber(); } /// /// Gets the used to supply error text. /// /// The used to supply error text. public IdentityErrorDescriber Describer { get; private set; } /// /// Validates a password as an asynchronous operation. /// /// The to retrieve the properties from. /// The user whose password should be validated. /// The password supplied for validation /// The task object representing the asynchronous operation. public virtual Task ValidateAsync(UserManager manager, TUser user, string password) { if (password == null) { throw new ArgumentNullException(nameof(password)); } if (manager == null) { throw new ArgumentNullException(nameof(manager)); } var errors = new List(); var options = manager.Options.Password; if (string.IsNullOrWhiteSpace(password) || password.Length < options.RequiredLength) { errors.Add(Describer.PasswordTooShort(options.RequiredLength)); } if (options.RequireNonLetterOrDigit && password.All(IsLetterOrDigit)) { errors.Add(Describer.PasswordRequiresNonLetterAndDigit()); } if (options.RequireDigit && !password.Any(IsDigit)) { errors.Add(Describer.PasswordRequiresDigit()); } if (options.RequireLowercase && !password.Any(IsLower)) { errors.Add(Describer.PasswordRequiresLower()); } if (options.RequireUppercase && !password.Any(IsUpper)) { errors.Add(Describer.PasswordRequiresUpper()); } return Task.FromResult(errors.Count == 0 ? IdentityResult.Success : IdentityResult.Failed(errors.ToArray())); } /// /// Returns a flag indicting whether the supplied character is a digit. /// /// The character to check if it is a digit. /// True if the character is a digit, otherwise false. public virtual bool IsDigit(char c) { return c >= '0' && c <= '9'; } /// /// Returns a flag indicting whether the supplied character is a lower case ASCII letter. /// /// The character to check if it is a lower case ASCII letter. /// True if the character is a lower case ASCII letter, otherwise false. public virtual bool IsLower(char c) { return c >= 'a' && c <= 'z'; } /// /// Returns a flag indicting whether the supplied character is an upper case ASCII letter. /// /// The character to check if it is an upper case ASCII letter. /// True if the character is an upper case ASCII letter, otherwise false. public virtual bool IsUpper(char c) { return c >= 'A' && c <= 'Z'; } /// /// Returns a flag indicting whether the supplied character is an ASCII letter or digit. /// /// The character to check if it is an ASCII letter or digit. /// True if the character is an ASCII letter or digit, otherwise false. public virtual bool IsLetterOrDigit(char c) { return IsUpper(c) || IsLower(c) || IsDigit(c); } } }