public PasswordResult ValidatePassword(string username, string password) { List <RuleResult> ruleResults = new List <RuleResult>(); foreach (var rule in this.passwordRules) { RuleResult ruleResult = rule.CheckPassword(username, password); ruleResults.Add(ruleResult); if (rule.BreakOnFailure && !ruleResult.Passed) { // This is a "Break on Failure" rule that has failed, // so we want to break out of the loop break; } } PasswordResult passwordResults = new PasswordResult(); passwordResults.ValidPassword = ruleResults.All(r => r.Passed); passwordResults.Messages = ruleResults .Where(r => !r.Passed) .Where(r => !String.IsNullOrWhiteSpace(r.Message)) .Select(r => r.Message).ToList(); return(passwordResults); }
/// <summary> /// Checks if a password is valid (acceptable) by running it through some rules /// </summary> /// <param name="username">A String of the username the password is for</param> /// <param name="password">A String of the password to be checked</param> /// <returns>A PasswordResult object indicating if the password meets all of the established rules</returns> public PasswordResult ValidatePassword(string username, string password) { PasswordResult results = new PasswordResult(); results.ValidPassword = false; if (String.IsNullOrEmpty(password)) { results.Messages.Add("A password value must be provided"); return(results); } else if (password.Length < 8) { results.Messages.Add("The password must be 8 characters in length or greater"); return(results); } else if (!Regex.IsMatch(password, "[A-Z]+", RegexOptions.IgnoreCase)) { results.Messages.Add("The password must contain at least one letter"); return(results); } else if (!Regex.IsMatch(password, "[0-9]+")) { results.Messages.Add("The password must contain at least one number"); return(results); } String usernameRegex = String.Format("({0})+", username); if (Regex.IsMatch(password, usernameRegex, RegexOptions.IgnoreCase)) { results.Messages.Add($"Your username of {username} may not be used as part of the password"); return(results); } if (this.HasPasswordBeenUsedBefore(username, password)) { results.Messages.Add($"You have entered a password that you have used before. Please enter a new password"); return(results); } return(results); }
/// <summary> /// Validates the password meets all of our rules /// </summary> /// <remarks> /// This method just iterates through all of the IPasswordRule objects in the list, /// running ech rule. Now this method (and class) is really more in a position of /// managing the entire process and not in implementing each rule. This is better /// from a separation of concerns point of view and makes things easier to test (i.e. /// we can test each rule individually and test the overall algorithm independantly /// /// <para> /// If we want to add, remove or change the order of the rules, this is much easier as well. /// And we can now define our list of rules outside of this class. For an example, take a look /// at the PasswordRuleValidatorTests class in the test project. /// </para> /// </remarks> /// <param name="username"></param> /// <param name="password"></param> /// <returns></returns> public PasswordResult ValidatePassword(string username, string password) { List <RuleResult> results = new List <RuleResult>(); foreach (var rule in this.passwordRules) { RuleResult ruleResult = rule.CheckPassword(username, password); if (!ruleResult.Passed) { PasswordResult passwordResults = new PasswordResult() { ValidPassword = false }; passwordResults.Messages.Add(ruleResult.Message); return(passwordResults); } } return(new PasswordResult() { ValidPassword = true }); }