using Microsoft.AspNetCore.Identity; using Sarand.BusinessMgr.Net.Standard.Base.Bus.Control; using Sarand.Net.Standard.Base.App; using Sarand.Net.Standard.Base.Utils; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace Sarand.Net.Standard.Base.Helpers { //======================================================================= public class SbmcPasswordHelper { //------------------------------------------------------------------- // Configuration parameters. public class PasswordParams { public int MinLength = 8; public int MinLengthNoComplexity = 12; } public static PasswordParams Params { get; } = new PasswordParams(); //------------------------------------------------------------------- /// Validate password against parameters. public static bool IsValidPassword(String password) { return GetPasswordStrength(password) >= 4; } /// /// Assess the password strength - 4+ is valid. /// 0 - Blank /// 1 - < min length - 2 [red] /// 1 - < min length and only 1 character type [red] /// 2 - < min length and only 2 character types [red] /// 2 - < min length without complexity - 2 and only 1 character type [red] /// 3 - < min length, min length with 3 character types [amber] /// 3 - Min length without complexity - 2 [amber] /// 3 - Other invalid passwords [amber] /// 4 - Min length with 4 character types [green] /// 4 - Min length without complexity [green] /// 5 - Min lenth + 2 with 4 character types [green] /// 5 - Min length without complexity with 3 character types [green] /// public static int GetPasswordStrength(String password) { String fn = "PasswordHelper.GetPasswordStrength"; // 0 - Blank. if (StringUtil.IsEmpty(password)) return 0; // Count number of different types of character. int characterTypeCount = 0; try { if (Regex.Matches(password, "[A-Z]").Count > 0) characterTypeCount++; if (Regex.Matches(password, "[a-z]").Count > 0) characterTypeCount++; if (Regex.Matches(password, "[0-9]").Count > 0) characterTypeCount++; if (Regex.Matches(password, "[^a-zA-Z0-9]").Count > 0) characterTypeCount++; } catch (Exception exc) { SaLogger.Debug(fn + " " + ExceptionUtil.GetLogMessage(exc)); } int passwordLength = StringUtil.GetLength(password); // 1 - Less than min length - 2; if (passwordLength < Params.MinLength - 2) return 1; // 1 - Less than min length and only 1 character type. if (passwordLength < Params.MinLength && characterTypeCount == 1) return 1; // 2 - Less than min length and only 2 character types. if (passwordLength < Params.MinLength && characterTypeCount == 2) return 2; // 2 - Less than min length without complexity - 2 and only 1 character type. if (passwordLength < Params.MinLengthNoComplexity - 2 && characterTypeCount == 1) return 2; // 3 - Less than minimum length. if (passwordLength < Params.MinLength) return 3; // 3 - Minimum length with only 3 character types. if (passwordLength >= Params.MinLength && passwordLength < Params.MinLengthNoComplexity && characterTypeCount == 3) return 3; // 3 - Minimum length without complexity - 2 with less than 4 character types. if (passwordLength >= Params.MinLengthNoComplexity - 2 && passwordLength < Params.MinLengthNoComplexity && characterTypeCount < 4) return 3; // 3 Catch-all - ensure only valid passwords score 4 or more. if (passwordLength < Params.MinLengthNoComplexity && characterTypeCount < 4) return 3; // 4 - Min length with 4 character types. if (passwordLength < Params.MinLengthNoComplexity) return 4; // 4 - Min length without complexity. if (passwordLength >= Params.MinLengthNoComplexity && passwordLength < Params.MinLengthNoComplexity + 2 && characterTypeCount < 4) return 4; // 5 - Anything more complex. return 5; } //------------------------------------------------------------------- private static PasswordHasher passwordHasher = new PasswordHasher(); /// Get the hashed value that corresponds to the password. public static String GetPasswordHash(SbmcUserAccount userAccount, String password) { return passwordHasher.HashPassword(userAccount, password); } /// Verify password against hashed value stored against user account. public static bool VerifyHashedPassword(SbmcUserAccount userAccount, String password) { return passwordHasher.VerifyHashedPassword(userAccount, userAccount.PasswordHashed, password) != PasswordVerificationResult.Failed; } /// Verify password against hashed value with user account as reference. public static bool VerifyHashedPassword(SbmcUserAccount userAccount, String password, String passwordHashed) { return passwordHasher.VerifyHashedPassword(userAccount, passwordHashed, password) != PasswordVerificationResult.Failed; } /// Check whether the password needs rehashing. public static bool PasswordRequiresRehash(SbmcUserAccount userAccount, String password) { return passwordHasher.VerifyHashedPassword(userAccount, userAccount.PasswordHashed, password) == PasswordVerificationResult.SuccessRehashNeeded; } //------------------------------------------------------------------- } //======================================================================= }