From 746dec6496db1ff0e7d27fcda386e58fe410e0f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rui=20Tom=C3=A9?= <108268980+r-tome@users.noreply.github.com> Date: Wed, 7 Jun 2023 09:56:31 +0100 Subject: [PATCH] [PM-1270] Throw error when removing master password reset policy with TDE enabled (#2964) * [PM-1270] Updated PolicyService to throw an exception in case TDE is enabled and the user is trying to turn off the master password reset policy or tries to remove auto-enrollment * [PM-1270] Added unit tests around the checks for turning off the master password reset policy or removing auto-enrollment * [PM-1270] Fixed existing unit test SaveAsync_NewPolicy_Created * [PM-1270] Removed unused method mock on unit test --- .../Services/Implementations/PolicyService.cs | 17 ++++++- test/Core.Test/Services/PolicyServiceTests.cs | 48 +++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/src/Core/Services/Implementations/PolicyService.cs b/src/Core/Services/Implementations/PolicyService.cs index ac54ff65d..a8411e419 100644 --- a/src/Core/Services/Implementations/PolicyService.cs +++ b/src/Core/Services/Implementations/PolicyService.cs @@ -75,6 +75,13 @@ public class PolicyService : IPolicyService } break; + case PolicyType.ResetPassword: + if (!policy.Enabled || policy.GetDataModel()?.AutoEnrollEnabled == false) + { + await RequiredBySsoTrustedDeviceEncryptionAsync(org); + } + break; + case PolicyType.MaximumVaultTimeout: if (policy.Enabled) { @@ -230,7 +237,6 @@ public class PolicyService : IPolicyService private async Task RequiredByKeyConnectorAsync(Organization org) { - var ssoConfig = await _ssoConfigRepository.GetByOrganizationIdAsync(org.Id); if (ssoConfig?.GetData()?.MemberDecryptionType == MemberDecryptionType.KeyConnector) { @@ -254,4 +260,13 @@ public class PolicyService : IPolicyService throw new BadRequestException("This policy is only available to 2020 Enterprise plans."); } } + + private async Task RequiredBySsoTrustedDeviceEncryptionAsync(Organization org) + { + var ssoConfig = await _ssoConfigRepository.GetByOrganizationIdAsync(org.Id); + if (ssoConfig?.GetData()?.MemberDecryptionType == MemberDecryptionType.TrustedDeviceEncryption) + { + throw new BadRequestException("Trusted device encryption is on and requires this policy."); + } + } } diff --git a/test/Core.Test/Services/PolicyServiceTests.cs b/test/Core.Test/Services/PolicyServiceTests.cs index 9f09e9262..3b4d9b1b8 100644 --- a/test/Core.Test/Services/PolicyServiceTests.cs +++ b/test/Core.Test/Services/PolicyServiceTests.cs @@ -6,6 +6,7 @@ using Bit.Core.Entities; using Bit.Core.Enums; using Bit.Core.Exceptions; using Bit.Core.Models.Data.Organizations.OrganizationUsers; +using Bit.Core.Models.Data.Organizations.Policies; using Bit.Core.Repositories; using Bit.Core.Services; using Bit.Test.Common.AutoFixture; @@ -208,6 +209,7 @@ public class PolicyServiceTests [PolicyFixtures.Policy(PolicyType.ResetPassword)] Policy policy, SutProvider sutProvider) { policy.Id = default; + policy.Data = null; SetupOrg(sutProvider, policy.OrganizationId, new Organization { @@ -396,6 +398,52 @@ public class PolicyServiceTests Assert.True(policy.RevisionDate - utcNow < TimeSpan.FromSeconds(1)); } + [Theory] + [BitAutoData(true, false)] + [BitAutoData(false, true)] + [BitAutoData(false, false)] + public async Task SaveAsync_PolicyRequiredByTrustedDeviceEncryption_DisablePolicyOrDisableAutomaticEnrollment_ThrowsBadRequest( + bool policyEnabled, + bool autoEnrollEnabled, + [PolicyFixtures.Policy(PolicyType.ResetPassword)] Policy policy, + SutProvider sutProvider) + { + policy.Enabled = policyEnabled; + policy.SetDataModel(new ResetPasswordDataModel + { + AutoEnrollEnabled = autoEnrollEnabled + }); + + SetupOrg(sutProvider, policy.OrganizationId, new Organization + { + Id = policy.OrganizationId, + UsePolicies = true, + }); + + var ssoConfig = new SsoConfig { Enabled = true }; + ssoConfig.SetData(new SsoConfigurationData { MemberDecryptionType = MemberDecryptionType.TrustedDeviceEncryption }); + + sutProvider.GetDependency() + .GetByOrganizationIdAsync(policy.OrganizationId) + .Returns(ssoConfig); + + var badRequestException = await Assert.ThrowsAsync( + () => sutProvider.Sut.SaveAsync(policy, + Substitute.For(), + Substitute.For(), + Guid.NewGuid())); + + Assert.Contains("Trusted device encryption is on and requires this policy.", badRequestException.Message, StringComparison.OrdinalIgnoreCase); + + await sutProvider.GetDependency() + .DidNotReceiveWithAnyArgs() + .UpsertAsync(default); + + await sutProvider.GetDependency() + .DidNotReceiveWithAnyArgs() + .LogPolicyEventAsync(default, default, default); + } + [Theory, BitAutoData] public async Task GetPoliciesApplicableToUserAsync_WithRequireSsoTypeFilter_WithDefaultOrganizationUserStatusFilter_ReturnsNoPolicies(Guid userId, SutProvider sutProvider) {