1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 15:42:48 -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:
Shane Melton
2023-04-17 07:35:47 -07:00
committed by GitHub
parent 972a500745
commit f2fad5513d
13 changed files with 149 additions and 12 deletions

View File

@ -6,6 +6,7 @@ using Bit.Api.Vault.Models.Response;
using Bit.Core.Auth.Services;
using Bit.Core.Entities;
using Bit.Core.Exceptions;
using Bit.Core.Models.Api.Response;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Settings;

View File

@ -12,6 +12,7 @@ using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Enums.Provider;
using Bit.Core.Exceptions;
using Bit.Core.Models.Api.Response;
using Bit.Core.Models.Business;
using Bit.Core.Models.Data;
using Bit.Core.Repositories;
@ -41,6 +42,7 @@ public class AccountsController : Controller
private readonly ISendRepository _sendRepository;
private readonly ISendService _sendService;
private readonly ICaptchaValidationService _captchaValidationService;
private readonly IPolicyService _policyService;
public AccountsController(
GlobalSettings globalSettings,
@ -54,7 +56,8 @@ public class AccountsController : Controller
IUserService userService,
ISendRepository sendRepository,
ISendService sendService,
ICaptchaValidationService captchaValidationService)
ICaptchaValidationService captchaValidationService,
IPolicyService policyService)
{
_cipherRepository = cipherRepository;
_folderRepository = folderRepository;
@ -68,6 +71,7 @@ public class AccountsController : Controller
_sendRepository = sendRepository;
_sendService = sendService;
_captchaValidationService = captchaValidationService;
_policyService = policyService;
}
#region DEPRECATED (Moved to Identity Service)
@ -261,7 +265,7 @@ public class AccountsController : Controller
}
[HttpPost("verify-password")]
public async Task PostVerifyPassword([FromBody] SecretVerificationRequestModel model)
public async Task<MasterPasswordPolicyResponseModel> PostVerifyPassword([FromBody] SecretVerificationRequestModel model)
{
var user = await _userService.GetUserByPrincipalAsync(User);
if (user == null)
@ -271,7 +275,9 @@ public class AccountsController : Controller
if (await _userService.CheckPasswordAsync(user, model.MasterPasswordHash))
{
return;
var policyData = await _policyService.GetMasterPasswordPolicyForUserAsync(user);
return new MasterPasswordPolicyResponseModel(policyData);
}
ModelState.AddModelError(nameof(model.MasterPasswordHash), "Invalid password.");

View File

@ -3,6 +3,7 @@ using Bit.Api.Models.Response;
using Bit.Core.Context;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Models.Api.Response;
using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Core.Settings;

View File

@ -1,33 +0,0 @@
using System.Text.Json;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Models.Api;
namespace Bit.Api.Models.Response;
public class PolicyResponseModel : ResponseModel
{
public PolicyResponseModel(Policy policy, string obj = "policy")
: base(obj)
{
if (policy == null)
{
throw new ArgumentNullException(nameof(policy));
}
Id = policy.Id.ToString();
OrganizationId = policy.OrganizationId.ToString();
Type = policy.Type;
Enabled = policy.Enabled;
if (!string.IsNullOrWhiteSpace(policy.Data))
{
Data = JsonSerializer.Deserialize<Dictionary<string, object>>(policy.Data);
}
}
public string Id { get; set; }
public string OrganizationId { get; set; }
public PolicyType Type { get; set; }
public Dictionary<string, object> Data { get; set; }
public bool Enabled { get; set; }
}

View File

@ -1,6 +1,7 @@
using Bit.Api.Models.Response;
using Bit.Core.Entities;
using Bit.Core.Models.Api;
using Bit.Core.Models.Api.Response;
using Bit.Core.Models.Data;
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Core.Settings;