// Copyright (c) Microsoft Open Technologies, Inc. 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; using System.Threading.Tasks; namespace Microsoft.AspNet.Identity { /// /// Used to validate some basic password policy like length and number of non alphanumerics /// public class PasswordValidator : IPasswordValidator where TUser : class { public PasswordValidator(IdentityErrorDescriber errors = null) { Describer = errors ?? new IdentityErrorDescriber(); } public IdentityErrorDescriber Describer { get; private set; } /// /// Ensures that the password is of the required length and meets the configured requirements /// /// /// /// /// public virtual Task ValidateAsync(UserManager manager, TUser user, string password, CancellationToken cancellationToken = default(CancellationToken)) { if (password == null) { throw new ArgumentNullException("password"); } if (manager == null) { throw new ArgumentNullException("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 true if the character is a digit between '0' and '9' /// /// /// public virtual bool IsDigit(char c) { return c >= '0' && c <= '9'; } /// /// Returns true if the character is between 'a' and 'z' /// /// /// public virtual bool IsLower(char c) { return c >= 'a' && c <= 'z'; } /// /// Returns true if the character is between 'A' and 'Z' /// /// /// public virtual bool IsUpper(char c) { return c >= 'A' && c <= 'Z'; } /// /// Returns true if the character is upper, lower, or a digit /// /// /// public virtual bool IsLetterOrDigit(char c) { return IsUpper(c) || IsLower(c) || IsDigit(c); } } }