1
0
mirror of https://github.com/bitwarden/mobile.git synced 2025-01-09 19:17:42 +01:00

[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) if (storedKeyHash != null)
{ {
passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(MasterPassword, key); passwordValid = await _cryptoService.CompareAndUpdateKeyHashAsync(MasterPassword, key);
enforcedMasterPasswordOptions = await _policyService.GetMasterPasswordPolicyOptions();
} }
else else
{ {
@ -336,7 +337,8 @@ namespace Bit.App.Pages
await _stateService.SetPinProtectedKeyAsync(await _cryptoService.EncryptAsync(key.Key, pinKey)); 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 // Save the ForcePasswordResetReason to force a password reset after unlock
await _stateService.SetForcePasswordResetReasonAsync( 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() public async Task LogOutAsync()
{ {
var confirmed = await _platformUtilsService.ShowDialogAsync(AppResources.LogoutConfirmation, 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); Task<bool> PolicyAppliesToUser(PolicyType policyType, Func<Policy, bool> policyFilter = null, string userId = null);
int? GetPolicyInt(Policy policy, string key); int? GetPolicyInt(Policy policy, string key);
Task<bool> ShouldShowVaultFilterAsync(); 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 localHashedPassword = await _cryptoService.HashPasswordAsync(masterPassword, key, HashPurpose.LocalAuthorization);
var result = await LogInHelperAsync(email, hashedPassword, localHashedPassword, null, null, null, key, null, null, null, captchaToken); 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)) if (!string.IsNullOrEmpty(_authedUserId))
{ {
@ -168,28 +168,6 @@ namespace Bit.Core.Services
return result; 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) public async Task<AuthResult> LogInPasswordlessAsync(string email, string accessCode, string authRequestId, byte[] decryptionKey, string userKeyCiphered, string localHashedPasswordCiphered)
{ {
var decKey = await _cryptoService.RsaDecryptAsync(userKeyCiphered, decryptionKey); var decKey = await _cryptoService.RsaDecryptAsync(userKeyCiphered, decryptionKey);

View File

@ -14,15 +14,18 @@ namespace Bit.Core.Services
{ {
private readonly IStateService _stateService; private readonly IStateService _stateService;
private readonly IOrganizationService _organizationService; private readonly IOrganizationService _organizationService;
private readonly IPasswordGenerationService _passwordGenerationService;
private IEnumerable<Policy> _policyCache; private IEnumerable<Policy> _policyCache;
public PolicyService( public PolicyService(
IStateService stateService, IStateService stateService,
IOrganizationService organizationService) IOrganizationService organizationService,
IPasswordGenerationService passwordGenerationService)
{ {
_stateService = stateService; _stateService = stateService;
_organizationService = organizationService; _organizationService = organizationService;
_passwordGenerationService = passwordGenerationService;
} }
public void ClearCache() public void ClearCache()
@ -182,6 +185,30 @@ namespace Bit.Core.Services
return true; 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, public Tuple<ResetPasswordPolicyOptions, bool> GetResetPasswordPolicyOptions(IEnumerable<Policy> policies,
string orgId) string orgId)
{ {