mirror of
https://github.com/bitwarden/server.git
synced 2025-07-03 00:52:49 -05:00
[AC-1070] Enforce master password policy on login (#2714)
* [EC-1070] Add API endpoint to retrieve all policies for the current user The additional API endpoint is required to avoid forcing a full sync call before every login for master password policy enforcement on login. * [EC-1070] Add MasterPasswordPolicyData model * [EC-1070] Move PolicyResponseModel to Core project The response model is used by both the Identity and Api projects. * [EC-1070] Supply master password polices as a custom identity token response * [EC-1070] Include master password policies in 2FA token response * [EC-1070] Add response model to verify-password endpoint that includes master password policies * [AC-1070] Introduce MasterPasswordPolicyResponseModel * [AC-1070] Add policy service method to retrieve a user's master password policy * [AC-1070] User new policy service method - Update BaseRequestValidator - Update AccountsController for /verify-password endpoint - Update VerifyMasterPasswordResponseModel to accept MasterPasswordPolicyData * [AC-1070] Cleanup new policy service method - Use User object instead of Guid - Remove TODO message - Use `PolicyRepository.GetManyByTypeApplicableToUserIdAsync` instead of filtering locally * [AC-1070] Cleanup MasterPasswordPolicy models - Remove default values from both models - Add missing `RequireLower` - Fix mismatched properties in `CombineWith` method - Make properties nullable in response model * [AC-1070] Remove now un-used GET /policies endpoint * [AC-1070] Update policy service method to use GetManyByUserIdAsync * [AC-1070] Ensure existing value is not null before comparison * [AC-1070] Remove redundant VerifyMasterPasswordResponse model * [AC-1070] Fix service typo in constructor
This commit is contained in:
@ -11,6 +11,7 @@ using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Identity;
|
||||
using Bit.Core.Models.Api;
|
||||
using Bit.Core.Models.Api.Response;
|
||||
using Bit.Core.Models.Data.Organizations;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
@ -38,6 +39,7 @@ public abstract class BaseRequestValidator<T> where T : class
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly IPolicyRepository _policyRepository;
|
||||
private readonly IUserRepository _userRepository;
|
||||
private readonly IPolicyService _policyService;
|
||||
|
||||
public BaseRequestValidator(
|
||||
UserManager<User> userManager,
|
||||
@ -54,7 +56,8 @@ public abstract class BaseRequestValidator<T> where T : class
|
||||
ICurrentContext currentContext,
|
||||
GlobalSettings globalSettings,
|
||||
IPolicyRepository policyRepository,
|
||||
IUserRepository userRepository)
|
||||
IUserRepository userRepository,
|
||||
IPolicyService policyService)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_deviceRepository = deviceRepository;
|
||||
@ -71,6 +74,7 @@ public abstract class BaseRequestValidator<T> where T : class
|
||||
_globalSettings = globalSettings;
|
||||
_policyRepository = policyRepository;
|
||||
_userRepository = userRepository;
|
||||
_policyService = policyService;
|
||||
}
|
||||
|
||||
protected async Task ValidateAsync(T context, ValidatedTokenRequest request,
|
||||
@ -181,6 +185,7 @@ public abstract class BaseRequestValidator<T> where T : class
|
||||
customResponse.Add("Key", user.Key);
|
||||
}
|
||||
|
||||
customResponse.Add("MasterPasswordPolicy", await GetMasterPasswordPolicy(user));
|
||||
customResponse.Add("ForcePasswordReset", user.ForcePasswordReset);
|
||||
customResponse.Add("ResetMasterPassword", string.IsNullOrWhiteSpace(user.MasterPassword));
|
||||
customResponse.Add("Kdf", (byte)user.Kdf);
|
||||
@ -239,7 +244,8 @@ public abstract class BaseRequestValidator<T> where T : class
|
||||
new Dictionary<string, object>
|
||||
{
|
||||
{ "TwoFactorProviders", providers.Keys },
|
||||
{ "TwoFactorProviders2", providers }
|
||||
{ "TwoFactorProviders2", providers },
|
||||
{ "MasterPasswordPolicy", await GetMasterPasswordPolicy(user) }
|
||||
});
|
||||
|
||||
if (enabledProviders.Count() == 1 && enabledProviders.First().Key == TwoFactorProviderType.Email)
|
||||
@ -568,4 +574,18 @@ public abstract class BaseRequestValidator<T> where T : class
|
||||
var failedLoginCount = user?.FailedLoginCount ?? 0;
|
||||
return unknownDevice && failedLoginCeiling > 0 && failedLoginCount == failedLoginCeiling;
|
||||
}
|
||||
|
||||
private async Task<MasterPasswordPolicyResponseModel> GetMasterPasswordPolicy(User user)
|
||||
{
|
||||
// Check current context/cache to see if user is in any organizations, avoids extra DB call if not
|
||||
var orgs = (await _currentContext.OrganizationMembershipAsync(_organizationUserRepository, user.Id))
|
||||
.ToList();
|
||||
|
||||
if (!orgs.Any())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new MasterPasswordPolicyResponseModel(await _policyService.GetMasterPasswordPolicyForUserAsync(user));
|
||||
}
|
||||
}
|
||||
|
@ -36,11 +36,12 @@ public class CustomTokenRequestValidator : BaseRequestValidator<CustomTokenReque
|
||||
GlobalSettings globalSettings,
|
||||
IPolicyRepository policyRepository,
|
||||
ISsoConfigRepository ssoConfigRepository,
|
||||
IUserRepository userRepository)
|
||||
IUserRepository userRepository,
|
||||
IPolicyService policyService)
|
||||
: base(userManager, deviceRepository, deviceService, userService, eventService,
|
||||
organizationDuoWebTokenProvider, organizationRepository, organizationUserRepository,
|
||||
applicationCacheService, mailService, logger, currentContext, globalSettings, policyRepository,
|
||||
userRepository)
|
||||
userRepository, policyService)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_ssoConfigRepository = ssoConfigRepository;
|
||||
|
@ -38,11 +38,12 @@ public class ResourceOwnerPasswordValidator : BaseRequestValidator<ResourceOwner
|
||||
IPolicyRepository policyRepository,
|
||||
ICaptchaValidationService captchaValidationService,
|
||||
IAuthRequestRepository authRequestRepository,
|
||||
IUserRepository userRepository)
|
||||
IUserRepository userRepository,
|
||||
IPolicyService policyService)
|
||||
: base(userManager, deviceRepository, deviceService, userService, eventService,
|
||||
organizationDuoWebTokenProvider, organizationRepository, organizationUserRepository,
|
||||
applicationCacheService, mailService, logger, currentContext, globalSettings, policyRepository,
|
||||
userRepository)
|
||||
userRepository, policyService)
|
||||
{
|
||||
_userManager = userManager;
|
||||
_userService = userService;
|
||||
|
Reference in New Issue
Block a user