diff --git a/src/App/Pages/Accounts/LockPageViewModel.cs b/src/App/Pages/Accounts/LockPageViewModel.cs
index ad38b5965..5cda53e20 100644
--- a/src/App/Pages/Accounts/LockPageViewModel.cs
+++ b/src/App/Pages/Accounts/LockPageViewModel.cs
@@ -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
}
}
- ///
- /// Checks if the master password requires updating to meet the enforced policy requirements
- ///
- ///
- private async Task 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,
diff --git a/src/Core/Abstractions/IPolicyService.cs b/src/Core/Abstractions/IPolicyService.cs
index caabeca3d..23d833b75 100644
--- a/src/Core/Abstractions/IPolicyService.cs
+++ b/src/Core/Abstractions/IPolicyService.cs
@@ -21,5 +21,14 @@ namespace Bit.Core.Abstractions
Task PolicyAppliesToUser(PolicyType policyType, Func policyFilter = null, string userId = null);
int? GetPolicyInt(Policy policy, string key);
Task ShouldShowVaultFilterAsync();
+
+ ///
+ /// Checks if the master password requires updating to meet the enforced policy requirements
+ ///
+ ///
+ /// The user's email, used to help evaluate password strength
+ ///
+ Task RequirePasswordChangeOnLoginAsync(string masterPassword, string email,
+ MasterPasswordPolicyOptions enforcedOptions);
}
}
diff --git a/src/Core/Services/AuthService.cs b/src/Core/Services/AuthService.cs
index a9a0170c0..aae2d9c3e 100644
--- a/src/Core/Services/AuthService.cs
+++ b/src/Core/Services/AuthService.cs
@@ -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;
}
- ///
- /// Evaluates the supplied master password against the master password policy provided by the Identity response.
- ///
- ///
- ///
- /// True if the master password does NOT meet any policy requirements, false otherwise (or if no policy present)
- private async Task 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 LogInPasswordlessAsync(string email, string accessCode, string authRequestId, byte[] decryptionKey, string userKeyCiphered, string localHashedPasswordCiphered)
{
var decKey = await _cryptoService.RsaDecryptAsync(userKeyCiphered, decryptionKey);
diff --git a/src/Core/Services/PolicyService.cs b/src/Core/Services/PolicyService.cs
index 218a1ba99..b0d81acac 100644
--- a/src/Core/Services/PolicyService.cs
+++ b/src/Core/Services/PolicyService.cs
@@ -14,15 +14,18 @@ namespace Bit.Core.Services
{
private readonly IStateService _stateService;
private readonly IOrganizationService _organizationService;
+ private readonly IPasswordGenerationService _passwordGenerationService;
private IEnumerable _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 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 GetResetPasswordPolicyOptions(IEnumerable policies,
string orgId)