[AC-1070] Move shared RequirePasswordChangeOnLogin method into PolicyService

This commit is contained in:
Shane Melton 2023-03-10 17:05:01 -08:00
parent e32135cd5d
commit e4feac130f
No known key found for this signature in database
4 changed files with 42 additions and 57 deletions

View File

@ -303,6 +303,7 @@ namespace Bit.App.Pages
if (storedKeyHash != null)
{
passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(MasterPassword, key);
enforcedMasterPasswordOptions = await _policyService.GetMasterPasswordPolicyOptions();
}
else
{
@ -310,7 +311,7 @@ namespace Bit.App.Pages
var keyHash = await _cryptoService.HashPasswordAsync(MasterPassword, key, HashPurpose.ServerAuthorization);
var request = new PasswordVerificationRequest();
request.MasterPasswordHash = keyHash;
try
{
var response = await _apiService.PostAccountVerifyPasswordAsync(request);
@ -336,7 +337,8 @@ namespace Bit.App.Pages
await _stateService.SetPinProtectedKeyAsync(await _cryptoService.EncryptAsync(key.Key, pinKey));
}
if (await RequirePasswordChangeAsync(enforcedMasterPasswordOptions))
if (await _policyService.RequirePasswordChangeOnLoginAsync(MasterPassword, _email,
enforcedMasterPasswordOptions))
{
// Save the ForcePasswordResetReason to force a password reset after unlock
await _stateService.SetForcePasswordResetReasonAsync(
@ -367,37 +369,6 @@ namespace Bit.App.Pages
}
}
/// <summary>
/// Checks if the master password requires updating to meet the enforced policy requirements
/// </summary>
/// <param name="options"></param>
private async Task<bool> RequirePasswordChangeAsync(MasterPasswordPolicyOptions options = null)
{
// If no policy options are provided, attempt to load them from the policy service
var enforcedOptions = options ?? await _policyService.GetMasterPasswordPolicyOptions();
// No policy to enforce on login/unlock
if (!(enforcedOptions is { EnforceOnLogin: true }))
{
return false;
}
var strength = _passwordGenerationService.PasswordStrength(
MasterPassword, _passwordGenerationService.GetPasswordStrengthUserInput(_email))?.Score;
if (!strength.HasValue)
{
_logger.Error("Unable to evaluate master password strength during unlock");
return false;
}
return !await _policyService.EvaluateMasterPassword(
strength.Value,
MasterPassword,
enforcedOptions
);
}
public async Task LogOutAsync()
{
var confirmed = await _platformUtilsService.ShowDialogAsync(AppResources.LogoutConfirmation,

View File

@ -21,5 +21,14 @@ namespace Bit.Core.Abstractions
Task<bool> PolicyAppliesToUser(PolicyType policyType, Func<Policy, bool> policyFilter = null, string userId = null);
int? GetPolicyInt(Policy policy, string key);
Task<bool> ShouldShowVaultFilterAsync();
/// <summary>
/// Checks if the master password requires updating to meet the enforced policy requirements
/// </summary>
/// <param name="masterPassword"></param>
/// <param name="email">The user's email, used to help evaluate password strength</param>
/// <param name="enforcedOptions"></param>
Task<bool> RequirePasswordChangeOnLoginAsync(string masterPassword, string email,
MasterPasswordPolicyOptions enforcedOptions);
}
}

View File

@ -149,7 +149,7 @@ namespace Bit.Core.Services
var localHashedPassword = await _cryptoService.HashPasswordAsync(masterPassword, key, HashPurpose.LocalAuthorization);
var result = await LogInHelperAsync(email, hashedPassword, localHashedPassword, null, null, null, key, null, null, null, captchaToken);
if (await RequirePasswordChange(email, masterPassword))
if (await _policyService.RequirePasswordChangeOnLoginAsync(masterPassword, email, _masterPasswordPolicy))
{
if (!string.IsNullOrEmpty(_authedUserId))
{
@ -168,28 +168,6 @@ namespace Bit.Core.Services
return result;
}
/// <summary>
/// Evaluates the supplied master password against the master password policy provided by the Identity response.
/// </summary>
/// <param name="email"></param>
/// <param name="masterPassword"></param>
/// <returns>True if the master password does NOT meet any policy requirements, false otherwise (or if no policy present)</returns>
private async Task<bool> RequirePasswordChange(string email, string masterPassword)
{
// No policy with EnforceOnLogin enabled, we're done.
if (!(_masterPasswordPolicy is { EnforceOnLogin: true }))
{
return false;
}
var passwordStrength = _passwordGenerationService.PasswordStrength(
masterPassword,
_passwordGenerationService.GetPasswordStrengthUserInput(email)
).Score;
return !await _policyService.EvaluateMasterPassword(passwordStrength, masterPassword, _masterPasswordPolicy);
}
public async Task<AuthResult> LogInPasswordlessAsync(string email, string accessCode, string authRequestId, byte[] decryptionKey, string userKeyCiphered, string localHashedPasswordCiphered)
{
var decKey = await _cryptoService.RsaDecryptAsync(userKeyCiphered, decryptionKey);

View File

@ -14,15 +14,18 @@ namespace Bit.Core.Services
{
private readonly IStateService _stateService;
private readonly IOrganizationService _organizationService;
private readonly IPasswordGenerationService _passwordGenerationService;
private IEnumerable<Policy> _policyCache;
public PolicyService(
IStateService stateService,
IOrganizationService organizationService)
IOrganizationService organizationService,
IPasswordGenerationService passwordGenerationService)
{
_stateService = stateService;
_organizationService = organizationService;
_passwordGenerationService = passwordGenerationService;
}
public void ClearCache()
@ -181,6 +184,30 @@ namespace Bit.Core.Services
return true;
}
public async Task<bool> RequirePasswordChangeOnLoginAsync(string masterPassword, string email,
MasterPasswordPolicyOptions enforcedOptions)
{
// No policy to enforce on login/unlock
if (!(enforcedOptions is { EnforceOnLogin: true }))
{
return false;
}
var strength = _passwordGenerationService.PasswordStrength(
masterPassword, _passwordGenerationService.GetPasswordStrengthUserInput(email))?.Score;
if (!strength.HasValue)
{
return false;
}
return !await EvaluateMasterPassword(
strength.Value,
masterPassword,
enforcedOptions
);
}
public Tuple<ResetPasswordPolicyOptions, bool> GetResetPasswordPolicyOptions(IEnumerable<Policy> policies,
string orgId)