139 lines
5.6 KiB
C#
139 lines
5.6 KiB
C#
using Microsoft.AspNetCore.Identity;
|
|
using Sarand.Net.Standard.Base.App;
|
|
using Sarand.Net.Standard.Base.Core;
|
|
using Sarand.Net.Standard.Base.Utils;
|
|
using Saxonite.Net.Standard.Base.Bus;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
|
|
namespace Saxonite.Net.Standard.Base.Helpers
|
|
{
|
|
//=======================================================================
|
|
public class SaxPasswordHelper
|
|
{
|
|
//-------------------------------------------------------------------
|
|
// Configuration parameters.
|
|
public class PasswordParams
|
|
{
|
|
public int MinLength = 8;
|
|
public int MinLengthNoComplexity = 12;
|
|
}
|
|
public static PasswordParams Params { get; } = new PasswordParams();
|
|
|
|
//-------------------------------------------------------------------
|
|
/// <summary>Validate password against parameters.</summary>
|
|
public static bool IsValidPassword(String password)
|
|
{
|
|
return GetPasswordStrength(password) >= 4;
|
|
}
|
|
/// <summary>
|
|
/// Assess the password strength - 4+ is valid.
|
|
/// <para>0 - Blank</para>
|
|
/// <para>1 - < min length - 2 [red]</para>
|
|
/// <para>1 - < min length and only 1 character type [red]</para>
|
|
/// <para>2 - < min length and only 2 character types [red]</para>
|
|
/// <para>2 - < min length without complexity - 2 and only 1 character type [red]</para>
|
|
/// <para>3 - < min length, min length with 3 character types [amber]</para>
|
|
/// <para>3 - Min length without complexity - 2 [amber]</para>
|
|
/// <para>3 - Other invalid passwords [amber]</para>
|
|
/// <para>4 - Min length with 4 character types [green]</para>
|
|
/// <para>4 - Min length without complexity [green]</para>
|
|
/// <para>5 - Min lenth + 2 with 4 character types [green]</para>
|
|
/// <para>5 - Min length without complexity with 3 character types [green]</para>
|
|
/// </summary>
|
|
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<SaxUserAccount> passwordHasher = new PasswordHasher<SaxUserAccount>();
|
|
/// <summary>Get the hashed value that corresponds to the password.</summary>
|
|
public static String GetPasswordHash(SaxUserAccount userAccount, String password)
|
|
{
|
|
return passwordHasher.HashPassword(userAccount, password);
|
|
}
|
|
/// <summary>Verify password against hashed value stored against user account.</summary>
|
|
public static bool VerifyHashedPassword(SaxUserAccount userAccount, String password)
|
|
{
|
|
return passwordHasher.VerifyHashedPassword(userAccount, userAccount.PasswordHashed, password) != PasswordVerificationResult.Failed;
|
|
}
|
|
/// <summary>Verify password against hashed value with user account as reference.</summary>
|
|
public static bool VerifyHashedPassword(SaxUserAccount userAccount, String password, String passwordHashed)
|
|
{
|
|
return passwordHasher.VerifyHashedPassword(userAccount, passwordHashed, password) != PasswordVerificationResult.Failed;
|
|
}
|
|
/// <summary>Check whether the password needs rehashing.</summary>
|
|
public static bool PasswordRequiresRehash(SaxUserAccount userAccount, String password)
|
|
{
|
|
return passwordHasher.VerifyHashedPassword(userAccount, userAccount.PasswordHashed, password) == PasswordVerificationResult.SuccessRehashNeeded;
|
|
}
|
|
|
|
//-------------------------------------------------------------------
|
|
}
|
|
//=======================================================================
|
|
}
|