1
0
mirror of https://github.com/bitwarden/server synced 2025-12-13 14:53:34 +00:00

[PM-26690] Wire VNextSavePolicyCommand behind PolicyValidatorsRefactor feature flag (#6483)

* Add PolicyValidatorsRefactor constant to FeatureFlagKeys in Constants.cs

* Add Metadata property and ToSavePolicyModel method to PolicyUpdateRequestModel

* Refactor PoliciesController to utilize IVNextSavePolicyCommand based on feature flag

- Added IFeatureService and IVNextSavePolicyCommand dependencies to PoliciesController.
- Updated PutVNext method to conditionally use VNextSavePolicyCommand or SavePolicyCommand based on the PolicyValidatorsRefactor feature flag.
- Enhanced unit tests to verify behavior for both enabled and disabled states of the feature flag.

* Update public PoliciesController to to utilize IVNextSavePolicyCommand based on feature flag

- Introduced IFeatureService and IVNextSavePolicyCommand to manage policy saving based on the PolicyValidatorsRefactor feature flag.
- Updated the Put method to conditionally use the new VNextSavePolicyCommand or the legacy SavePolicyCommand.
- Added unit tests to validate the behavior of the Put method for both enabled and disabled states of the feature flag.

* Refactor VerifyOrganizationDomainCommand to utilize IVNextSavePolicyCommand based on feature flag

- Added IFeatureService and IVNextSavePolicyCommand dependencies to VerifyOrganizationDomainCommand.
- Updated EnableSingleOrganizationPolicyAsync method to conditionally use VNextSavePolicyCommand or SavePolicyCommand based on the PolicyValidatorsRefactor feature flag.
- Enhanced unit tests to validate the behavior when the feature flag is enabled.

* Enhance SsoConfigService to utilize IVNextSavePolicyCommand based on feature flag

- Added IFeatureService and IVNextSavePolicyCommand dependencies to SsoConfigService.
- Updated SaveAsync method to conditionally use VNextSavePolicyCommand or SavePolicyCommand based on the PolicyValidatorsRefactor feature flag.
- Added unit tests to validate the behavior when the feature flag is enabled.

* Refactor SavePolicyModel to simplify constructor usage by removing EmptyMetadataModel parameter. Update related usages across the codebase to reflect the new constructor overloads.

* Update PolicyUpdateRequestModel to make Metadata property nullable for improved null safety
This commit is contained in:
Rui Tomé
2025-11-06 11:35:07 +00:00
committed by GitHub
parent 3668a445e5
commit 4aed97b76b
19 changed files with 426 additions and 59 deletions

View File

@@ -12,6 +12,7 @@ using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums; using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies; using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Auth.Models.Business.Tokenables; using Bit.Core.Auth.Models.Business.Tokenables;
using Bit.Core.Context; using Bit.Core.Context;
@@ -41,8 +42,9 @@ public class PoliciesController : Controller
private readonly IDataProtectorTokenFactory<OrgUserInviteTokenable> _orgUserInviteTokenDataFactory; private readonly IDataProtectorTokenFactory<OrgUserInviteTokenable> _orgUserInviteTokenDataFactory;
private readonly IPolicyRepository _policyRepository; private readonly IPolicyRepository _policyRepository;
private readonly IUserService _userService; private readonly IUserService _userService;
private readonly IFeatureService _featureService;
private readonly ISavePolicyCommand _savePolicyCommand; private readonly ISavePolicyCommand _savePolicyCommand;
private readonly IVNextSavePolicyCommand _vNextSavePolicyCommand;
public PoliciesController(IPolicyRepository policyRepository, public PoliciesController(IPolicyRepository policyRepository,
IOrganizationUserRepository organizationUserRepository, IOrganizationUserRepository organizationUserRepository,
@@ -53,7 +55,9 @@ public class PoliciesController : Controller
IDataProtectorTokenFactory<OrgUserInviteTokenable> orgUserInviteTokenDataFactory, IDataProtectorTokenFactory<OrgUserInviteTokenable> orgUserInviteTokenDataFactory,
IOrganizationHasVerifiedDomainsQuery organizationHasVerifiedDomainsQuery, IOrganizationHasVerifiedDomainsQuery organizationHasVerifiedDomainsQuery,
IOrganizationRepository organizationRepository, IOrganizationRepository organizationRepository,
ISavePolicyCommand savePolicyCommand) IFeatureService featureService,
ISavePolicyCommand savePolicyCommand,
IVNextSavePolicyCommand vNextSavePolicyCommand)
{ {
_policyRepository = policyRepository; _policyRepository = policyRepository;
_organizationUserRepository = organizationUserRepository; _organizationUserRepository = organizationUserRepository;
@@ -65,7 +69,9 @@ public class PoliciesController : Controller
_organizationRepository = organizationRepository; _organizationRepository = organizationRepository;
_orgUserInviteTokenDataFactory = orgUserInviteTokenDataFactory; _orgUserInviteTokenDataFactory = orgUserInviteTokenDataFactory;
_organizationHasVerifiedDomainsQuery = organizationHasVerifiedDomainsQuery; _organizationHasVerifiedDomainsQuery = organizationHasVerifiedDomainsQuery;
_featureService = featureService;
_savePolicyCommand = savePolicyCommand; _savePolicyCommand = savePolicyCommand;
_vNextSavePolicyCommand = vNextSavePolicyCommand;
} }
[HttpGet("{type}")] [HttpGet("{type}")]
@@ -221,7 +227,9 @@ public class PoliciesController : Controller
{ {
var savePolicyRequest = await model.ToSavePolicyModelAsync(orgId, _currentContext); var savePolicyRequest = await model.ToSavePolicyModelAsync(orgId, _currentContext);
var policy = await _savePolicyCommand.VNextSaveAsync(savePolicyRequest); var policy = _featureService.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor) ?
await _vNextSavePolicyCommand.SaveAsync(savePolicyRequest) :
await _savePolicyCommand.VNextSaveAsync(savePolicyRequest);
return new PolicyResponseModel(policy); return new PolicyResponseModel(policy);
} }

View File

@@ -5,11 +5,15 @@ using System.Net;
using Bit.Api.AdminConsole.Public.Models.Request; using Bit.Api.AdminConsole.Public.Models.Request;
using Bit.Api.AdminConsole.Public.Models.Response; using Bit.Api.AdminConsole.Public.Models.Response;
using Bit.Api.Models.Public.Response; using Bit.Api.Models.Public.Response;
using Bit.Core;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums; using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies; using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.AdminConsole.Services; using Bit.Core.AdminConsole.Services;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Services;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
@@ -22,18 +26,24 @@ public class PoliciesController : Controller
private readonly IPolicyRepository _policyRepository; private readonly IPolicyRepository _policyRepository;
private readonly IPolicyService _policyService; private readonly IPolicyService _policyService;
private readonly ICurrentContext _currentContext; private readonly ICurrentContext _currentContext;
private readonly IFeatureService _featureService;
private readonly ISavePolicyCommand _savePolicyCommand; private readonly ISavePolicyCommand _savePolicyCommand;
private readonly IVNextSavePolicyCommand _vNextSavePolicyCommand;
public PoliciesController( public PoliciesController(
IPolicyRepository policyRepository, IPolicyRepository policyRepository,
IPolicyService policyService, IPolicyService policyService,
ICurrentContext currentContext, ICurrentContext currentContext,
ISavePolicyCommand savePolicyCommand) IFeatureService featureService,
ISavePolicyCommand savePolicyCommand,
IVNextSavePolicyCommand vNextSavePolicyCommand)
{ {
_policyRepository = policyRepository; _policyRepository = policyRepository;
_policyService = policyService; _policyService = policyService;
_currentContext = currentContext; _currentContext = currentContext;
_featureService = featureService;
_savePolicyCommand = savePolicyCommand; _savePolicyCommand = savePolicyCommand;
_vNextSavePolicyCommand = vNextSavePolicyCommand;
} }
/// <summary> /// <summary>
@@ -86,9 +96,18 @@ public class PoliciesController : Controller
[ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.BadRequest)] [ProducesResponseType(typeof(ErrorResponseModel), (int)HttpStatusCode.BadRequest)]
[ProducesResponseType((int)HttpStatusCode.NotFound)] [ProducesResponseType((int)HttpStatusCode.NotFound)]
public async Task<IActionResult> Put(PolicyType type, [FromBody] PolicyUpdateRequestModel model) public async Task<IActionResult> Put(PolicyType type, [FromBody] PolicyUpdateRequestModel model)
{
Policy policy;
if (_featureService.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor))
{
var savePolicyModel = model.ToSavePolicyModel(_currentContext.OrganizationId!.Value, type);
policy = await _vNextSavePolicyCommand.SaveAsync(savePolicyModel);
}
else
{ {
var policyUpdate = model.ToPolicyUpdate(_currentContext.OrganizationId!.Value, type); var policyUpdate = model.ToPolicyUpdate(_currentContext.OrganizationId!.Value, type);
var policy = await _savePolicyCommand.SaveAsync(policyUpdate); policy = await _savePolicyCommand.SaveAsync(policyUpdate);
}
var response = new PolicyResponseModel(policy); var response = new PolicyResponseModel(policy);
return new JsonResult(response); return new JsonResult(response);

View File

@@ -8,6 +8,8 @@ namespace Bit.Api.AdminConsole.Public.Models.Request;
public class PolicyUpdateRequestModel : PolicyBaseModel public class PolicyUpdateRequestModel : PolicyBaseModel
{ {
public Dictionary<string, object>? Metadata { get; set; }
public PolicyUpdate ToPolicyUpdate(Guid organizationId, PolicyType type) public PolicyUpdate ToPolicyUpdate(Guid organizationId, PolicyType type)
{ {
var serializedData = PolicyDataValidator.ValidateAndSerialize(Data, type); var serializedData = PolicyDataValidator.ValidateAndSerialize(Data, type);
@@ -21,4 +23,22 @@ public class PolicyUpdateRequestModel : PolicyBaseModel
PerformedBy = new SystemUser(EventSystemUser.PublicApi) PerformedBy = new SystemUser(EventSystemUser.PublicApi)
}; };
} }
public SavePolicyModel ToSavePolicyModel(Guid organizationId, PolicyType type)
{
var serializedData = PolicyDataValidator.ValidateAndSerialize(Data, type);
var policyUpdate = new PolicyUpdate
{
Type = type,
OrganizationId = organizationId,
Data = serializedData,
Enabled = Enabled.GetValueOrDefault()
};
var performedBy = new SystemUser(EventSystemUser.PublicApi);
var metadata = PolicyDataValidator.ValidateAndDeserializeMetadata(Metadata, type);
return new SavePolicyModel(policyUpdate, performedBy, metadata);
}
} }

View File

@@ -6,6 +6,7 @@ using Bit.Core.AdminConsole.Models.Data;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains.Interfaces;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies; using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models; using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
@@ -24,7 +25,9 @@ public class VerifyOrganizationDomainCommand(
IEventService eventService, IEventService eventService,
IGlobalSettings globalSettings, IGlobalSettings globalSettings,
ICurrentContext currentContext, ICurrentContext currentContext,
IFeatureService featureService,
ISavePolicyCommand savePolicyCommand, ISavePolicyCommand savePolicyCommand,
IVNextSavePolicyCommand vNextSavePolicyCommand,
IMailService mailService, IMailService mailService,
IOrganizationUserRepository organizationUserRepository, IOrganizationUserRepository organizationUserRepository,
IOrganizationRepository organizationRepository, IOrganizationRepository organizationRepository,
@@ -131,15 +134,26 @@ public class VerifyOrganizationDomainCommand(
await SendVerifiedDomainUserEmailAsync(domain); await SendVerifiedDomainUserEmailAsync(domain);
} }
private async Task EnableSingleOrganizationPolicyAsync(Guid organizationId, IActingUser actingUser) => private async Task EnableSingleOrganizationPolicyAsync(Guid organizationId, IActingUser actingUser)
await savePolicyCommand.SaveAsync( {
new PolicyUpdate var policyUpdate = new PolicyUpdate
{ {
OrganizationId = organizationId, OrganizationId = organizationId,
Type = PolicyType.SingleOrg, Type = PolicyType.SingleOrg,
Enabled = true, Enabled = true,
PerformedBy = actingUser PerformedBy = actingUser
}); };
if (featureService.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor))
{
var savePolicyModel = new SavePolicyModel(policyUpdate, actingUser);
await vNextSavePolicyCommand.SaveAsync(savePolicyModel);
}
else
{
await savePolicyCommand.SaveAsync(policyUpdate);
}
}
private async Task SendVerifiedDomainUserEmailAsync(OrganizationDomain domain) private async Task SendVerifiedDomainUserEmailAsync(OrganizationDomain domain)
{ {

View File

@@ -4,5 +4,19 @@ using Bit.Core.AdminConsole.Models.Data;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models; namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
public record SavePolicyModel(PolicyUpdate PolicyUpdate, IActingUser? PerformedBy, IPolicyMetadataModel Metadata) public record SavePolicyModel(PolicyUpdate PolicyUpdate, IActingUser? PerformedBy, IPolicyMetadataModel Metadata)
{
public SavePolicyModel(PolicyUpdate PolicyUpdate)
: this(PolicyUpdate, null, new EmptyMetadataModel())
{ {
} }
public SavePolicyModel(PolicyUpdate PolicyUpdate, IActingUser performedBy)
: this(PolicyUpdate, performedBy, new EmptyMetadataModel())
{
}
public SavePolicyModel(PolicyUpdate PolicyUpdate, IPolicyMetadataModel metadata)
: this(PolicyUpdate, null, metadata)
{
}
}

View File

@@ -3,9 +3,11 @@
using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums; using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies; using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies; using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models; using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Auth.Entities; using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Enums; using Bit.Core.Auth.Enums;
@@ -24,7 +26,9 @@ public class SsoConfigService : ISsoConfigService
private readonly IOrganizationRepository _organizationRepository; private readonly IOrganizationRepository _organizationRepository;
private readonly IOrganizationUserRepository _organizationUserRepository; private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly IEventService _eventService; private readonly IEventService _eventService;
private readonly IFeatureService _featureService;
private readonly ISavePolicyCommand _savePolicyCommand; private readonly ISavePolicyCommand _savePolicyCommand;
private readonly IVNextSavePolicyCommand _vNextSavePolicyCommand;
public SsoConfigService( public SsoConfigService(
ISsoConfigRepository ssoConfigRepository, ISsoConfigRepository ssoConfigRepository,
@@ -32,14 +36,18 @@ public class SsoConfigService : ISsoConfigService
IOrganizationRepository organizationRepository, IOrganizationRepository organizationRepository,
IOrganizationUserRepository organizationUserRepository, IOrganizationUserRepository organizationUserRepository,
IEventService eventService, IEventService eventService,
ISavePolicyCommand savePolicyCommand) IFeatureService featureService,
ISavePolicyCommand savePolicyCommand,
IVNextSavePolicyCommand vNextSavePolicyCommand)
{ {
_ssoConfigRepository = ssoConfigRepository; _ssoConfigRepository = ssoConfigRepository;
_policyRepository = policyRepository; _policyRepository = policyRepository;
_organizationRepository = organizationRepository; _organizationRepository = organizationRepository;
_organizationUserRepository = organizationUserRepository; _organizationUserRepository = organizationUserRepository;
_eventService = eventService; _eventService = eventService;
_featureService = featureService;
_savePolicyCommand = savePolicyCommand; _savePolicyCommand = savePolicyCommand;
_vNextSavePolicyCommand = vNextSavePolicyCommand;
} }
public async Task SaveAsync(SsoConfig config, Organization organization) public async Task SaveAsync(SsoConfig config, Organization organization)
@@ -67,13 +75,12 @@ public class SsoConfigService : ISsoConfigService
// Automatically enable account recovery, SSO required, and single org policies if trusted device encryption is selected // Automatically enable account recovery, SSO required, and single org policies if trusted device encryption is selected
if (config.GetData().MemberDecryptionType == MemberDecryptionType.TrustedDeviceEncryption) if (config.GetData().MemberDecryptionType == MemberDecryptionType.TrustedDeviceEncryption)
{ {
var singleOrgPolicy = new PolicyUpdate
await _savePolicyCommand.SaveAsync(new()
{ {
OrganizationId = config.OrganizationId, OrganizationId = config.OrganizationId,
Type = PolicyType.SingleOrg, Type = PolicyType.SingleOrg,
Enabled = true Enabled = true
}); };
var resetPasswordPolicy = new PolicyUpdate var resetPasswordPolicy = new PolicyUpdate
{ {
@@ -82,14 +89,27 @@ public class SsoConfigService : ISsoConfigService
Enabled = true, Enabled = true,
}; };
resetPasswordPolicy.SetDataModel(new ResetPasswordDataModel { AutoEnrollEnabled = true }); resetPasswordPolicy.SetDataModel(new ResetPasswordDataModel { AutoEnrollEnabled = true });
await _savePolicyCommand.SaveAsync(resetPasswordPolicy);
await _savePolicyCommand.SaveAsync(new() var requireSsoPolicy = new PolicyUpdate
{ {
OrganizationId = config.OrganizationId, OrganizationId = config.OrganizationId,
Type = PolicyType.RequireSso, Type = PolicyType.RequireSso,
Enabled = true Enabled = true
}); };
if (_featureService.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor))
{
var performedBy = new SystemUser(EventSystemUser.Unknown);
await _vNextSavePolicyCommand.SaveAsync(new SavePolicyModel(singleOrgPolicy, performedBy));
await _vNextSavePolicyCommand.SaveAsync(new SavePolicyModel(resetPasswordPolicy, performedBy));
await _vNextSavePolicyCommand.SaveAsync(new SavePolicyModel(requireSsoPolicy, performedBy));
}
else
{
await _savePolicyCommand.SaveAsync(singleOrgPolicy);
await _savePolicyCommand.SaveAsync(resetPasswordPolicy);
await _savePolicyCommand.SaveAsync(requireSsoPolicy);
}
} }
await LogEventsAsync(config, oldConfig); await LogEventsAsync(config, oldConfig);

View File

@@ -143,6 +143,7 @@ public static class FeatureFlagKeys
public const string AutomaticConfirmUsers = "pm-19934-auto-confirm-organization-users"; public const string AutomaticConfirmUsers = "pm-19934-auto-confirm-organization-users";
public const string PM23845_VNextApplicationCache = "pm-24957-refactor-memory-application-cache"; public const string PM23845_VNextApplicationCache = "pm-24957-refactor-memory-application-cache";
public const string AccountRecoveryCommand = "pm-25581-prevent-provider-account-recovery"; public const string AccountRecoveryCommand = "pm-25581-prevent-provider-account-recovery";
public const string PolicyValidatorsRefactor = "pm-26423-refactor-policy-side-effects";
/* Auth Team */ /* Auth Team */
public const string TwoFactorExtensionDataPersistence = "pm-9115-two-factor-extension-data-persistence"; public const string TwoFactorExtensionDataPersistence = "pm-9115-two-factor-extension-data-persistence";

View File

@@ -0,0 +1,87 @@
using Bit.Api.AdminConsole.Public.Controllers;
using Bit.Api.AdminConsole.Public.Models.Request;
using Bit.Core;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
using Bit.Core.Context;
using Bit.Core.Services;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using Xunit;
namespace Bit.Api.Test.AdminConsole.Public.Controllers;
[ControllerCustomize(typeof(PoliciesController))]
[SutProviderCustomize]
public class PoliciesControllerTests
{
[Theory]
[BitAutoData]
public async Task Put_WhenPolicyValidatorsRefactorEnabled_UsesVNextSavePolicyCommand(
Guid organizationId,
PolicyType policyType,
PolicyUpdateRequestModel model,
Policy policy,
SutProvider<PoliciesController> sutProvider)
{
// Arrange
policy.Data = null;
sutProvider.GetDependency<ICurrentContext>()
.OrganizationId.Returns(organizationId);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor)
.Returns(true);
sutProvider.GetDependency<IVNextSavePolicyCommand>()
.SaveAsync(Arg.Any<SavePolicyModel>())
.Returns(policy);
// Act
await sutProvider.Sut.Put(policyType, model);
// Assert
await sutProvider.GetDependency<IVNextSavePolicyCommand>()
.Received(1)
.SaveAsync(Arg.Is<SavePolicyModel>(m =>
m.PolicyUpdate.OrganizationId == organizationId &&
m.PolicyUpdate.Type == policyType &&
m.PolicyUpdate.Enabled == model.Enabled.GetValueOrDefault() &&
m.PerformedBy is SystemUser));
}
[Theory]
[BitAutoData]
public async Task Put_WhenPolicyValidatorsRefactorDisabled_UsesLegacySavePolicyCommand(
Guid organizationId,
PolicyType policyType,
PolicyUpdateRequestModel model,
Policy policy,
SutProvider<PoliciesController> sutProvider)
{
// Arrange
policy.Data = null;
sutProvider.GetDependency<ICurrentContext>()
.OrganizationId.Returns(organizationId);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor)
.Returns(false);
sutProvider.GetDependency<ISavePolicyCommand>()
.SaveAsync(Arg.Any<PolicyUpdate>())
.Returns(policy);
// Act
await sutProvider.Sut.Put(policyType, model);
// Assert
await sutProvider.GetDependency<ISavePolicyCommand>()
.Received(1)
.SaveAsync(Arg.Is<PolicyUpdate>(p =>
p.OrganizationId == organizationId &&
p.Type == policyType &&
p.Enabled == model.Enabled));
}
}

View File

@@ -1,10 +1,15 @@
using System.Security.Claims; using System.Security.Claims;
using System.Text.Json; using System.Text.Json;
using Bit.Api.AdminConsole.Controllers; using Bit.Api.AdminConsole.Controllers;
using Bit.Api.AdminConsole.Models.Request;
using Bit.Api.AdminConsole.Models.Response.Organizations; using Bit.Api.AdminConsole.Models.Response.Organizations;
using Bit.Core;
using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums; using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies; using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Auth.Models.Business.Tokenables; using Bit.Core.Auth.Models.Business.Tokenables;
using Bit.Core.Context; using Bit.Core.Context;
@@ -455,4 +460,98 @@ public class PoliciesControllerTests
Assert.Equal(enabledPolicy.Type, expectedPolicy.Type); Assert.Equal(enabledPolicy.Type, expectedPolicy.Type);
Assert.Equal(enabledPolicy.Enabled, expectedPolicy.Enabled); Assert.Equal(enabledPolicy.Enabled, expectedPolicy.Enabled);
} }
[Theory]
[BitAutoData]
public async Task PutVNext_WhenPolicyValidatorsRefactorEnabled_UsesVNextSavePolicyCommand(
SutProvider<PoliciesController> sutProvider, Guid orgId,
SavePolicyRequest model, Policy policy, Guid userId)
{
// Arrange
policy.Data = null;
sutProvider.GetDependency<ICurrentContext>()
.UserId
.Returns(userId);
sutProvider.GetDependency<ICurrentContext>()
.OrganizationOwner(orgId)
.Returns(true);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor)
.Returns(true);
sutProvider.GetDependency<IVNextSavePolicyCommand>()
.SaveAsync(Arg.Any<SavePolicyModel>())
.Returns(policy);
// Act
var result = await sutProvider.Sut.PutVNext(orgId, model);
// Assert
await sutProvider.GetDependency<IVNextSavePolicyCommand>()
.Received(1)
.SaveAsync(Arg.Is<SavePolicyModel>(
m => m.PolicyUpdate.OrganizationId == orgId &&
m.PolicyUpdate.Type == model.Policy.Type &&
m.PolicyUpdate.Enabled == model.Policy.Enabled &&
m.PerformedBy.UserId == userId &&
m.PerformedBy.IsOrganizationOwnerOrProvider == true));
await sutProvider.GetDependency<ISavePolicyCommand>()
.DidNotReceiveWithAnyArgs()
.VNextSaveAsync(default);
Assert.NotNull(result);
Assert.Equal(policy.Id, result.Id);
Assert.Equal(policy.Type, result.Type);
}
[Theory]
[BitAutoData]
public async Task PutVNext_WhenPolicyValidatorsRefactorDisabled_UsesSavePolicyCommand(
SutProvider<PoliciesController> sutProvider, Guid orgId,
SavePolicyRequest model, Policy policy, Guid userId)
{
// Arrange
policy.Data = null;
sutProvider.GetDependency<ICurrentContext>()
.UserId
.Returns(userId);
sutProvider.GetDependency<ICurrentContext>()
.OrganizationOwner(orgId)
.Returns(true);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor)
.Returns(false);
sutProvider.GetDependency<ISavePolicyCommand>()
.VNextSaveAsync(Arg.Any<SavePolicyModel>())
.Returns(policy);
// Act
var result = await sutProvider.Sut.PutVNext(orgId, model);
// Assert
await sutProvider.GetDependency<ISavePolicyCommand>()
.Received(1)
.VNextSaveAsync(Arg.Is<SavePolicyModel>(
m => m.PolicyUpdate.OrganizationId == orgId &&
m.PolicyUpdate.Type == model.Policy.Type &&
m.PolicyUpdate.Enabled == model.Policy.Enabled &&
m.PerformedBy.UserId == userId &&
m.PerformedBy.IsOrganizationOwnerOrProvider == true));
await sutProvider.GetDependency<IVNextSavePolicyCommand>()
.DidNotReceiveWithAnyArgs()
.SaveAsync(default);
Assert.NotNull(result);
Assert.Equal(policy.Id, result.Id);
Assert.Equal(policy.Type, result.Type);
}
} }

View File

@@ -4,6 +4,7 @@ using Bit.Core.AdminConsole.Models.Data;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationDomains;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies; using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models; using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
using Bit.Core.Context; using Bit.Core.Context;
using Bit.Core.Entities; using Bit.Core.Entities;
using Bit.Core.Enums; using Bit.Core.Enums;
@@ -191,6 +192,37 @@ public class VerifyOrganizationDomainCommandTests
x.PerformedBy.UserId == userId)); x.PerformedBy.UserId == userId));
} }
[Theory, BitAutoData]
public async Task UserVerifyOrganizationDomainAsync_WhenPolicyValidatorsRefactorFlagEnabled_UsesVNextSavePolicyCommand(
OrganizationDomain domain, Guid userId, SutProvider<VerifyOrganizationDomainCommand> sutProvider)
{
sutProvider.GetDependency<IOrganizationDomainRepository>()
.GetClaimedDomainsByDomainNameAsync(domain.DomainName)
.Returns([]);
sutProvider.GetDependency<IDnsResolverService>()
.ResolveAsync(domain.DomainName, domain.Txt)
.Returns(true);
sutProvider.GetDependency<ICurrentContext>()
.UserId.Returns(userId);
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor)
.Returns(true);
_ = await sutProvider.Sut.UserVerifyOrganizationDomainAsync(domain);
await sutProvider.GetDependency<IVNextSavePolicyCommand>()
.Received(1)
.SaveAsync(Arg.Is<SavePolicyModel>(m =>
m.PolicyUpdate.Type == PolicyType.SingleOrg &&
m.PolicyUpdate.OrganizationId == domain.OrganizationId &&
m.PolicyUpdate.Enabled &&
m.PerformedBy is StandardUser &&
m.PerformedBy.UserId == userId));
}
[Theory, BitAutoData] [Theory, BitAutoData]
public async Task UserVerifyOrganizationDomainAsync_WhenDomainIsNotVerified_ThenSingleOrgPolicyShouldNotBeEnabled( public async Task UserVerifyOrganizationDomainAsync_WhenDomainIsNotVerified_ThenSingleOrgPolicyShouldNotBeEnabled(
OrganizationDomain domain, SutProvider<VerifyOrganizationDomainCommand> sutProvider) OrganizationDomain domain, SutProvider<VerifyOrganizationDomainCommand> sutProvider)

View File

@@ -92,7 +92,7 @@ public class FreeFamiliesForEnterprisePolicyValidatorTests
.GetManyBySponsoringOrganizationAsync(policyUpdate.OrganizationId) .GetManyBySponsoringOrganizationAsync(policyUpdate.OrganizationId)
.Returns(organizationSponsorships); .Returns(organizationSponsorships);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
await sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, policy); await sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, policy);
@@ -120,7 +120,7 @@ public class FreeFamiliesForEnterprisePolicyValidatorTests
.GetManyBySponsoringOrganizationAsync(policyUpdate.OrganizationId) .GetManyBySponsoringOrganizationAsync(policyUpdate.OrganizationId)
.Returns(organizationSponsorships); .Returns(organizationSponsorships);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
await sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, policy); await sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, policy);

View File

@@ -32,7 +32,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation) .IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
.Returns(false); .Returns(false);
var policyRequest = new SavePolicyModel(policyUpdate, null, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName)); var policyRequest = new SavePolicyModel(policyUpdate, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
// Act // Act
await sutProvider.Sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState); await sutProvider.Sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
@@ -58,7 +58,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation) .IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
.Returns(true); .Returns(true);
var policyRequest = new SavePolicyModel(policyUpdate, null, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName)); var policyRequest = new SavePolicyModel(policyUpdate, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
// Act // Act
await sutProvider.Sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState); await sutProvider.Sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
@@ -84,7 +84,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation) .IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
.Returns(true); .Returns(true);
var policyRequest = new SavePolicyModel(policyUpdate, null, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName)); var policyRequest = new SavePolicyModel(policyUpdate, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
// Act // Act
await sutProvider.Sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState); await sutProvider.Sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
@@ -110,7 +110,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
var collectionRepository = Substitute.For<ICollectionRepository>(); var collectionRepository = Substitute.For<ICollectionRepository>();
var sut = ArrangeSut(factory, policyRepository, collectionRepository); var sut = ArrangeSut(factory, policyRepository, collectionRepository);
var policyRequest = new SavePolicyModel(policyUpdate, null, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName)); var policyRequest = new SavePolicyModel(policyUpdate, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
// Act // Act
await sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState); await sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
@@ -199,7 +199,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
var collectionRepository = Substitute.For<ICollectionRepository>(); var collectionRepository = Substitute.For<ICollectionRepository>();
var sut = ArrangeSut(factory, policyRepository, collectionRepository); var sut = ArrangeSut(factory, policyRepository, collectionRepository);
var policyRequest = new SavePolicyModel(policyUpdate, null, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName)); var policyRequest = new SavePolicyModel(policyUpdate, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
// Act // Act
await sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState); await sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
@@ -238,7 +238,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation) .IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
.Returns(true); .Returns(true);
var policyRequest = new SavePolicyModel(policyUpdate, null, metadata); var policyRequest = new SavePolicyModel(policyUpdate, metadata);
// Act // Act
await sutProvider.Sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState); await sutProvider.Sut.ExecuteSideEffectsAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
@@ -286,7 +286,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation) .IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
.Returns(false); .Returns(false);
var policyRequest = new SavePolicyModel(policyUpdate, null, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName)); var policyRequest = new SavePolicyModel(policyUpdate, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
// Act // Act
await sutProvider.Sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState); await sutProvider.Sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
@@ -312,7 +312,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation) .IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
.Returns(true); .Returns(true);
var policyRequest = new SavePolicyModel(policyUpdate, null, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName)); var policyRequest = new SavePolicyModel(policyUpdate, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
// Act // Act
await sutProvider.Sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState); await sutProvider.Sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
@@ -338,7 +338,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation) .IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
.Returns(true); .Returns(true);
var policyRequest = new SavePolicyModel(policyUpdate, null, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName)); var policyRequest = new SavePolicyModel(policyUpdate, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
// Act // Act
await sutProvider.Sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState); await sutProvider.Sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
@@ -364,7 +364,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
var collectionRepository = Substitute.For<ICollectionRepository>(); var collectionRepository = Substitute.For<ICollectionRepository>();
var sut = ArrangeSut(factory, policyRepository, collectionRepository); var sut = ArrangeSut(factory, policyRepository, collectionRepository);
var policyRequest = new SavePolicyModel(policyUpdate, null, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName)); var policyRequest = new SavePolicyModel(policyUpdate, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
// Act // Act
await sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState); await sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
@@ -404,7 +404,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
var collectionRepository = Substitute.For<ICollectionRepository>(); var collectionRepository = Substitute.For<ICollectionRepository>();
var sut = ArrangeSut(factory, policyRepository, collectionRepository); var sut = ArrangeSut(factory, policyRepository, collectionRepository);
var policyRequest = new SavePolicyModel(policyUpdate, null, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName)); var policyRequest = new SavePolicyModel(policyUpdate, new OrganizationModelOwnershipPolicyModel(_defaultUserCollectionName));
// Act // Act
await sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState); await sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState);
@@ -436,7 +436,7 @@ public class OrganizationDataOwnershipPolicyValidatorTests
.IsEnabled(FeatureFlagKeys.CreateDefaultLocation) .IsEnabled(FeatureFlagKeys.CreateDefaultLocation)
.Returns(true); .Returns(true);
var policyRequest = new SavePolicyModel(policyUpdate, null, metadata); var policyRequest = new SavePolicyModel(policyUpdate, metadata);
// Act // Act
await sutProvider.Sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState); await sutProvider.Sut.ExecutePostUpsertSideEffectAsync(policyRequest, postUpdatedPolicy, previousPolicyState);

View File

@@ -88,7 +88,7 @@ public class RequireSsoPolicyValidatorTests
.GetByOrganizationIdAsync(policyUpdate.OrganizationId) .GetByOrganizationIdAsync(policyUpdate.OrganizationId)
.Returns(ssoConfig); .Returns(ssoConfig);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy); var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
Assert.Contains("Key Connector is enabled", result, StringComparison.OrdinalIgnoreCase); Assert.Contains("Key Connector is enabled", result, StringComparison.OrdinalIgnoreCase);
@@ -109,7 +109,7 @@ public class RequireSsoPolicyValidatorTests
.GetByOrganizationIdAsync(policyUpdate.OrganizationId) .GetByOrganizationIdAsync(policyUpdate.OrganizationId)
.Returns(ssoConfig); .Returns(ssoConfig);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy); var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
Assert.Contains("Trusted device encryption is on", result, StringComparison.OrdinalIgnoreCase); Assert.Contains("Trusted device encryption is on", result, StringComparison.OrdinalIgnoreCase);
@@ -129,7 +129,7 @@ public class RequireSsoPolicyValidatorTests
.GetByOrganizationIdAsync(policyUpdate.OrganizationId) .GetByOrganizationIdAsync(policyUpdate.OrganizationId)
.Returns(ssoConfig); .Returns(ssoConfig);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy); var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
Assert.True(string.IsNullOrEmpty(result)); Assert.True(string.IsNullOrEmpty(result));

View File

@@ -94,7 +94,7 @@ public class ResetPasswordPolicyValidatorTests
.GetByOrganizationIdAsync(policyUpdate.OrganizationId) .GetByOrganizationIdAsync(policyUpdate.OrganizationId)
.Returns(ssoConfig); .Returns(ssoConfig);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy); var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
Assert.Contains("Trusted device encryption is on and requires this policy.", result, StringComparison.OrdinalIgnoreCase); Assert.Contains("Trusted device encryption is on and requires this policy.", result, StringComparison.OrdinalIgnoreCase);
@@ -118,7 +118,7 @@ public class ResetPasswordPolicyValidatorTests
.GetByOrganizationIdAsync(policyUpdate.OrganizationId) .GetByOrganizationIdAsync(policyUpdate.OrganizationId)
.Returns(ssoConfig); .Returns(ssoConfig);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy); var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
Assert.True(string.IsNullOrEmpty(result)); Assert.True(string.IsNullOrEmpty(result));

View File

@@ -162,7 +162,7 @@ public class SingleOrgPolicyValidatorTests
.GetByOrganizationIdAsync(policyUpdate.OrganizationId) .GetByOrganizationIdAsync(policyUpdate.OrganizationId)
.Returns(ssoConfig); .Returns(ssoConfig);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy); var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
Assert.Contains("Key Connector is enabled", result, StringComparison.OrdinalIgnoreCase); Assert.Contains("Key Connector is enabled", result, StringComparison.OrdinalIgnoreCase);
@@ -186,7 +186,7 @@ public class SingleOrgPolicyValidatorTests
.HasVerifiedDomainsAsync(policyUpdate.OrganizationId) .HasVerifiedDomainsAsync(policyUpdate.OrganizationId)
.Returns(false); .Returns(false);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy); var result = await sutProvider.Sut.ValidateAsync(savePolicyModel, policy);
Assert.True(string.IsNullOrEmpty(result)); Assert.True(string.IsNullOrEmpty(result));
@@ -256,7 +256,7 @@ public class SingleOrgPolicyValidatorTests
.RevokeNonCompliantOrganizationUsersAsync(Arg.Any<RevokeOrganizationUsersRequest>()) .RevokeNonCompliantOrganizationUsersAsync(Arg.Any<RevokeOrganizationUsersRequest>())
.Returns(new CommandResult()); .Returns(new CommandResult());
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
await sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, policy); await sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, policy);

View File

@@ -169,7 +169,7 @@ public class TwoFactorAuthenticationPolicyValidatorTests
(orgUserDetailUserWithout2Fa, false), (orgUserDetailUserWithout2Fa, false),
}); });
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
var exception = await Assert.ThrowsAsync<BadRequestException>(() => var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, policy)); sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, policy));
@@ -228,7 +228,7 @@ public class TwoFactorAuthenticationPolicyValidatorTests
.RevokeNonCompliantOrganizationUsersAsync(Arg.Any<RevokeOrganizationUsersRequest>()) .RevokeNonCompliantOrganizationUsersAsync(Arg.Any<RevokeOrganizationUsersRequest>())
.Returns(new CommandResult()); .Returns(new CommandResult());
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
// Act // Act
await sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, policy); await sutProvider.Sut.ExecutePreUpsertSideEffectAsync(savePolicyModel, policy);

View File

@@ -288,7 +288,7 @@ public class SavePolicyCommandTests
{ {
// Arrange // Arrange
var sutProvider = SutProviderFactory(); var sutProvider = SutProviderFactory();
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
currentPolicy.OrganizationId = policyUpdate.OrganizationId; currentPolicy.OrganizationId = policyUpdate.OrganizationId;
sutProvider.GetDependency<IPolicyRepository>() sutProvider.GetDependency<IPolicyRepository>()
@@ -332,7 +332,7 @@ public class SavePolicyCommandTests
var sutProvider = SutProviderFactory(); var sutProvider = SutProviderFactory();
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
sutProvider.GetDependency<IPolicyRepository>() sutProvider.GetDependency<IPolicyRepository>()
.GetByOrganizationIdTypeAsync(policyUpdate.OrganizationId, policyUpdate.Type) .GetByOrganizationIdTypeAsync(policyUpdate.OrganizationId, policyUpdate.Type)

View File

@@ -33,7 +33,7 @@ public class VNextSavePolicyCommandTests
fakePolicyValidationEvent fakePolicyValidationEvent
]); ]);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
var newPolicy = new Policy var newPolicy = new Policy
{ {
@@ -77,7 +77,7 @@ public class VNextSavePolicyCommandTests
fakePolicyValidationEvent fakePolicyValidationEvent
]); ]);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
currentPolicy.OrganizationId = policyUpdate.OrganizationId; currentPolicy.OrganizationId = policyUpdate.OrganizationId;
sutProvider.GetDependency<IPolicyRepository>() sutProvider.GetDependency<IPolicyRepository>()
@@ -117,7 +117,7 @@ public class VNextSavePolicyCommandTests
{ {
// Arrange // Arrange
var sutProvider = SutProviderFactory(); var sutProvider = SutProviderFactory();
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
sutProvider.GetDependency<IApplicationCacheService>() sutProvider.GetDependency<IApplicationCacheService>()
.GetOrganizationAbilityAsync(policyUpdate.OrganizationId) .GetOrganizationAbilityAsync(policyUpdate.OrganizationId)
@@ -137,7 +137,7 @@ public class VNextSavePolicyCommandTests
{ {
// Arrange // Arrange
var sutProvider = SutProviderFactory(); var sutProvider = SutProviderFactory();
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
sutProvider.GetDependency<IApplicationCacheService>() sutProvider.GetDependency<IApplicationCacheService>()
.GetOrganizationAbilityAsync(policyUpdate.OrganizationId) .GetOrganizationAbilityAsync(policyUpdate.OrganizationId)
@@ -167,7 +167,7 @@ public class VNextSavePolicyCommandTests
new FakeSingleOrgDependencyEvent() new FakeSingleOrgDependencyEvent()
]); ]);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
var requireSsoPolicy = new Policy var requireSsoPolicy = new Policy
{ {
@@ -202,7 +202,7 @@ public class VNextSavePolicyCommandTests
new FakeSingleOrgDependencyEvent() new FakeSingleOrgDependencyEvent()
]); ]);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
var requireSsoPolicy = new Policy var requireSsoPolicy = new Policy
{ {
@@ -237,7 +237,7 @@ public class VNextSavePolicyCommandTests
new FakeSingleOrgDependencyEvent() new FakeSingleOrgDependencyEvent()
]); ]);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
var requireSsoPolicy = new Policy var requireSsoPolicy = new Policy
{ {
@@ -271,7 +271,7 @@ public class VNextSavePolicyCommandTests
new FakeSingleOrgDependencyEvent() new FakeSingleOrgDependencyEvent()
]); ]);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
ArrangeOrganization(sutProvider, policyUpdate); ArrangeOrganization(sutProvider, policyUpdate);
sutProvider.GetDependency<IPolicyRepository>() sutProvider.GetDependency<IPolicyRepository>()
@@ -302,7 +302,7 @@ public class VNextSavePolicyCommandTests
new FakeVaultTimeoutDependencyEvent() new FakeVaultTimeoutDependencyEvent()
]); ]);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
ArrangeOrganization(sutProvider, policyUpdate); ArrangeOrganization(sutProvider, policyUpdate);
sutProvider.GetDependency<IPolicyRepository>() sutProvider.GetDependency<IPolicyRepository>()
@@ -331,7 +331,7 @@ public class VNextSavePolicyCommandTests
new FakeSingleOrgDependencyEvent() new FakeSingleOrgDependencyEvent()
]); ]);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
ArrangeOrganization(sutProvider, policyUpdate); ArrangeOrganization(sutProvider, policyUpdate);
sutProvider.GetDependency<IPolicyRepository>() sutProvider.GetDependency<IPolicyRepository>()
@@ -356,7 +356,7 @@ public class VNextSavePolicyCommandTests
fakePolicyValidationEvent fakePolicyValidationEvent
]); ]);
var savePolicyModel = new SavePolicyModel(policyUpdate, null, new EmptyMetadataModel()); var savePolicyModel = new SavePolicyModel(policyUpdate);
var singleOrgPolicy = new Policy var singleOrgPolicy = new Policy
{ {

View File

@@ -1,8 +1,10 @@
using Bit.Core.AdminConsole.Entities; using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums; using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies; using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies; using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models; using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Models;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyUpdateEvents.Interfaces;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Auth.Entities; using Bit.Core.Auth.Entities;
using Bit.Core.Auth.Enums; using Bit.Core.Auth.Enums;
@@ -12,6 +14,7 @@ using Bit.Core.Auth.Services;
using Bit.Core.Exceptions; using Bit.Core.Exceptions;
using Bit.Core.Models.Data.Organizations.OrganizationUsers; using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
using Bit.Test.Common.AutoFixture; using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes; using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute; using NSubstitute;
@@ -364,4 +367,54 @@ public class SsoConfigServiceTests
await sutProvider.GetDependency<ISsoConfigRepository>().ReceivedWithAnyArgs() await sutProvider.GetDependency<ISsoConfigRepository>().ReceivedWithAnyArgs()
.UpsertAsync(default); .UpsertAsync(default);
} }
[Theory, BitAutoData]
public async Task SaveAsync_Tde_WhenPolicyValidatorsRefactorEnabled_UsesVNextSavePolicyCommand(
SutProvider<SsoConfigService> sutProvider, Organization organization)
{
var ssoConfig = new SsoConfig
{
Id = default,
Data = new SsoConfigurationData
{
MemberDecryptionType = MemberDecryptionType.TrustedDeviceEncryption,
}.Serialize(),
Enabled = true,
OrganizationId = organization.Id,
};
sutProvider.GetDependency<IFeatureService>()
.IsEnabled(FeatureFlagKeys.PolicyValidatorsRefactor)
.Returns(true);
await sutProvider.Sut.SaveAsync(ssoConfig, organization);
await sutProvider.GetDependency<IVNextSavePolicyCommand>()
.Received(1)
.SaveAsync(Arg.Is<SavePolicyModel>(m =>
m.PolicyUpdate.Type == PolicyType.SingleOrg &&
m.PolicyUpdate.OrganizationId == organization.Id &&
m.PolicyUpdate.Enabled &&
m.PerformedBy is SystemUser));
await sutProvider.GetDependency<IVNextSavePolicyCommand>()
.Received(1)
.SaveAsync(Arg.Is<SavePolicyModel>(m =>
m.PolicyUpdate.Type == PolicyType.ResetPassword &&
m.PolicyUpdate.GetDataModel<ResetPasswordDataModel>().AutoEnrollEnabled &&
m.PolicyUpdate.OrganizationId == organization.Id &&
m.PolicyUpdate.Enabled &&
m.PerformedBy is SystemUser));
await sutProvider.GetDependency<IVNextSavePolicyCommand>()
.Received(1)
.SaveAsync(Arg.Is<SavePolicyModel>(m =>
m.PolicyUpdate.Type == PolicyType.RequireSso &&
m.PolicyUpdate.OrganizationId == organization.Id &&
m.PolicyUpdate.Enabled &&
m.PerformedBy is SystemUser));
await sutProvider.GetDependency<ISsoConfigRepository>().ReceivedWithAnyArgs()
.UpsertAsync(default);
}
} }