diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/AcceptOrgUserCommand.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/AcceptOrgUserCommand.cs index 2a24b8e5c5..b015e34f06 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/AcceptOrgUserCommand.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/AcceptOrgUserCommand.cs @@ -246,17 +246,10 @@ public class AcceptOrgUserCommand : IAcceptOrgUserCommand /// Thrown if the user does not have two-step login enabled. private async Task ValidateTwoFactorAuthenticationPolicyAsync(User user, Guid organizationId) { - var userTwoFactorEnabled = await _twoFactorIsEnabledQuery.TwoFactorIsEnabledAsync(user); - if (userTwoFactorEnabled) - { - // If the user has two-step login enabled, we skip checking the 2FA policies - return; - } + var twoFactorPolicyRequirement = await _policyRequirementQuery.GetAsync(user.Id); + var twoFactorRequiredForOrganization = twoFactorPolicyRequirement.IsTwoFactorRequiredForOrganization(organizationId); - var requirement = await _policyRequirementQuery.GetAsync(user.Id); - var canAcceptInvitation = requirement.CanAcceptInvitation(userTwoFactorEnabled, organizationId); - - if (!canAcceptInvitation) + if (twoFactorRequiredForOrganization && !await _twoFactorIsEnabledQuery.TwoFactorIsEnabledAsync(user)) { throw new BadRequestException("You cannot join this organization until you enable two-step login on your user account."); } diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/ConfirmOrganizationUserCommand.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/ConfirmOrganizationUserCommand.cs index 95fd676c02..da3308f064 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/ConfirmOrganizationUserCommand.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/ConfirmOrganizationUserCommand.cs @@ -194,14 +194,14 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand { if (userTwoFactorEnabled) { - // If the user has two-step login enabled, we skip checking the 2FA policies + // If the user has two-step login enabled, we skip checking the 2FA policy return; } - var requirement = await _policyRequirementQuery.GetAsync(user.Id); - var canBeConfirmed = requirement.CanBeConfirmed(userTwoFactorEnabled, organizationId); + var twoFactorPolicyRequirement = await _policyRequirementQuery.GetAsync(user.Id); + var twoFactorRequired = twoFactorPolicyRequirement.IsTwoFactorRequiredForOrganization(organizationId); - if (!canBeConfirmed) + if (twoFactorRequired) { throw new BadRequestException("User does not have two-step login enabled."); } diff --git a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/RestoreUser/v1/RestoreOrganizationUserCommand.cs b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/RestoreUser/v1/RestoreOrganizationUserCommand.cs index 0bae1c0675..257648da37 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/RestoreUser/v1/RestoreOrganizationUserCommand.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/OrganizationUsers/RestoreUser/v1/RestoreOrganizationUserCommand.cs @@ -276,7 +276,7 @@ public class RestoreOrganizationUserCommand( if (featureService.IsEnabled(FeatureFlagKeys.PolicyRequirements)) { var requirement = await policyRequirementQuery.GetAsync(userId); - twoFactorCompliant = requirement.CanBeRestored(userHasTwoFactorEnabled, orgUser.OrganizationId); + twoFactorCompliant = !requirement.IsTwoFactorRequiredForOrganization(orgUser.OrganizationId); } else { diff --git a/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyRequirements/RequireTwoFactorPolicyRequirement.cs b/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyRequirements/RequireTwoFactorPolicyRequirement.cs index 29611a4f30..0ac92838c6 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyRequirements/RequireTwoFactorPolicyRequirement.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyRequirements/RequireTwoFactorPolicyRequirement.cs @@ -16,53 +16,20 @@ public class RequireTwoFactorPolicyRequirement : IPolicyRequirement } /// - /// Determines if the user can accept an invitation to an organization. + /// Checks if two-factor authentication is required for the organization due to an active policy. /// - /// Whether the user has two-step login enabled. - /// The ID of the organization. - /// True if the user can accept the invitation, false otherwise. - public bool CanAcceptInvitation(bool twoFactorEnabled, Guid organizationId) => - twoFactorEnabled || - !_policyDetails.Any(p => p.OrganizationId == organizationId && - (p.OrganizationUserStatus is - OrganizationUserStatusType.Invited or - OrganizationUserStatusType.Accepted or - OrganizationUserStatusType.Confirmed)); - + /// The ID of the organization to check. + /// True if two-factor authentication is required for the organization, false otherwise. + /// + /// This does not check the user's membership status. + /// + public bool IsTwoFactorRequiredForOrganization(Guid organizationId) => + _policyDetails.Any(p => p.OrganizationId == organizationId); /// - /// Determines if the user can be confirmed in an organization. + /// Gets the active two-factor authentication policies for active memberships. /// - /// Whether the user has two-step login enabled. - /// The ID of the organization. - /// True if the user can be confirmed, false otherwise. - public bool CanBeConfirmed(bool twoFactorEnabled, Guid organizationId) => - twoFactorEnabled || - !_policyDetails.Any(p => p.OrganizationId == organizationId && - (p.OrganizationUserStatus is - OrganizationUserStatusType.Accepted or - OrganizationUserStatusType.Confirmed)); - - - /// - /// Determines if the user can be restored in an organization. - /// - /// Whether the user has two-step login enabled. - /// The ID of the organization. - /// True if the user can be restored, false otherwise. - public bool CanBeRestored(bool twoFactorEnabled, Guid organizationId) => - twoFactorEnabled || - !_policyDetails.Any(p => p.OrganizationId == organizationId && - (p.OrganizationUserStatus is - OrganizationUserStatusType.Revoked or - OrganizationUserStatusType.Invited or - OrganizationUserStatusType.Accepted or - OrganizationUserStatusType.Confirmed)); - - /// - /// Gets the two-factor policies for active memberships. - /// - /// The two-factor policies for active memberships. + /// The active two-factor authentication policies for active memberships. public IEnumerable TwoFactorPoliciesForActiveMemberships => _policyDetails.Where(p => p.OrganizationUserStatus is OrganizationUserStatusType.Accepted or diff --git a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/AcceptOrgUserCommandTests.cs b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/AcceptOrgUserCommandTests.cs index 8d8d42d48a..c6bddd197e 100644 --- a/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/AcceptOrgUserCommandTests.cs +++ b/test/Core.Test/AdminConsole/OrganizationFeatures/OrganizationUsers/AcceptOrgUserCommandTests.cs @@ -253,10 +253,6 @@ public class AcceptOrgUserCommandTests await sutProvider.Sut.AcceptOrgUserAsync(orgUser, user, _userService); - await sutProvider.GetDependency() - .DidNotReceiveWithAnyArgs() - .GetAsync(default); - await sutProvider.GetDependency() .Received(1) .ReplaceAsync(Arg.Is(ou => ou.Status == OrganizationUserStatusType.Accepted)); diff --git a/test/Core.Test/AdminConsole/OrganizationFeatures/Policies/PolicyRequirements/RequireTwoFactorPolicyRequirementFactoryTests.cs b/test/Core.Test/AdminConsole/OrganizationFeatures/Policies/PolicyRequirements/RequireTwoFactorPolicyRequirementFactoryTests.cs index 9739f9345e..f5a82afed7 100644 --- a/test/Core.Test/AdminConsole/OrganizationFeatures/Policies/PolicyRequirements/RequireTwoFactorPolicyRequirementFactoryTests.cs +++ b/test/Core.Test/AdminConsole/OrganizationFeatures/Policies/PolicyRequirements/RequireTwoFactorPolicyRequirementFactoryTests.cs @@ -11,24 +11,20 @@ namespace Bit.Core.Test.AdminConsole.OrganizationFeatures.Policies.PolicyRequire public class RequireTwoFactorPolicyRequirementFactoryTests { [Theory] - [BitAutoData(true)] - [BitAutoData(false)] - public void CanAcceptInvitation_WithNoPolicies_ReturnsTrue( - bool twoFactorEnabled, Guid organizationId, + [BitAutoData] + public void IsTwoFactorRequiredForOrganization_WithNoPolicies_ReturnsFalse( + Guid organizationId, SutProvider sutProvider) { var actual = sutProvider.Sut.Create([]); - Assert.True(actual.CanAcceptInvitation(twoFactorEnabled, organizationId)); + Assert.False(actual.IsTwoFactorRequiredForOrganization(organizationId)); } [Theory] - [BitAutoData(OrganizationUserStatusType.Revoked)] - [BitAutoData(OrganizationUserStatusType.Invited)] - [BitAutoData(OrganizationUserStatusType.Accepted)] - [BitAutoData(OrganizationUserStatusType.Confirmed)] - public void CanAcceptInvitation_WithTwoFactorEnabled_ReturnsTrue( - OrganizationUserStatusType userStatus, Guid organizationId, + [BitAutoData] + public void IsTwoFactorRequiredForOrganization_WithOrganizationPolicy_ReturnsTrue( + Guid organizationId, SutProvider sutProvider) { var actual = sutProvider.Sut.Create( @@ -37,179 +33,28 @@ public class RequireTwoFactorPolicyRequirementFactoryTests { OrganizationId = organizationId, PolicyType = PolicyType.TwoFactorAuthentication, - OrganizationUserStatus = userStatus } ]); - Assert.True(actual.CanAcceptInvitation(true, organizationId)); + Assert.True(actual.IsTwoFactorRequiredForOrganization(organizationId)); } [Theory] - [BitAutoData(OrganizationUserStatusType.Revoked)] - public void CanAcceptInvitation_WithExemptStatus_ReturnsTrue( - OrganizationUserStatusType userStatus, Guid organizationId, + [BitAutoData] + public void IsTwoFactorRequiredForOrganization_WithOtherOrganizationPolicy_ReturnsFalse( + Guid organizationId, SutProvider sutProvider) { var actual = sutProvider.Sut.Create( [ new PolicyDetails { - OrganizationId = organizationId, + OrganizationId = Guid.NewGuid(), PolicyType = PolicyType.TwoFactorAuthentication, - OrganizationUserStatus = userStatus - } + }, ]); - Assert.True(actual.CanAcceptInvitation(false, organizationId)); - } - - [Theory] - [BitAutoData(OrganizationUserStatusType.Invited)] - [BitAutoData(OrganizationUserStatusType.Accepted)] - [BitAutoData(OrganizationUserStatusType.Confirmed)] - public void CanAcceptInvitation_WithNonExemptStatus_ReturnsFalse( - OrganizationUserStatusType userStatus, Guid organizationId, - SutProvider sutProvider) - { - var actual = sutProvider.Sut.Create( - [ - new PolicyDetails - { - OrganizationId = organizationId, - PolicyType = PolicyType.TwoFactorAuthentication, - OrganizationUserStatus = userStatus - } - ]); - - Assert.False(actual.CanAcceptInvitation(false, organizationId)); - } - - [Theory] - [BitAutoData(true)] - [BitAutoData(false)] - public void CanBeConfirmed_WithNoPolicies_ReturnsTrue( - bool twoFactorEnabled, Guid organizationId, - SutProvider sutProvider) - { - var actual = sutProvider.Sut.Create([]); - - Assert.True(actual.CanBeConfirmed(twoFactorEnabled, organizationId)); - } - - [Theory] - [BitAutoData(OrganizationUserStatusType.Accepted)] - [BitAutoData(OrganizationUserStatusType.Confirmed)] - public void CanBeConfirmed_WithTwoFactorEnabled_ReturnsTrue( - OrganizationUserStatusType userStatus, Guid organizationId, - SutProvider sutProvider) - { - var actual = sutProvider.Sut.Create( - [ - new PolicyDetails - { - OrganizationId = organizationId, - PolicyType = PolicyType.TwoFactorAuthentication, - OrganizationUserStatus = userStatus - } - ]); - - Assert.True(actual.CanBeConfirmed(true, organizationId)); - } - - [Theory] - [BitAutoData(OrganizationUserStatusType.Revoked)] - [BitAutoData(OrganizationUserStatusType.Invited)] - public void CanBeConfirmed_WithExemptStatus_ReturnsTrue( - OrganizationUserStatusType userStatus, Guid organizationId, - SutProvider sutProvider) - { - var actual = sutProvider.Sut.Create( - [ - new PolicyDetails - { - OrganizationId = organizationId, - PolicyType = PolicyType.TwoFactorAuthentication, - OrganizationUserStatus = userStatus - } - ]); - - Assert.True(actual.CanBeConfirmed(false, organizationId)); - } - - [Theory] - [BitAutoData(OrganizationUserStatusType.Accepted)] - [BitAutoData(OrganizationUserStatusType.Confirmed)] - public void CanBeConfirmed_WithNonExemptStatus_ReturnsFalse( - OrganizationUserStatusType userStatus, Guid organizationId, - SutProvider sutProvider) - { - var actual = sutProvider.Sut.Create( - [ - new PolicyDetails - { - OrganizationId = organizationId, - PolicyType = PolicyType.TwoFactorAuthentication, - OrganizationUserStatus = userStatus - } - ]); - - Assert.False(actual.CanBeConfirmed(false, organizationId)); - } - - [Theory] - [BitAutoData(true)] - [BitAutoData(false)] - public void CanBeRestored_WithNoPolicies_ReturnsTrue( - bool twoFactorEnabled, Guid organizationId, - SutProvider sutProvider) - { - var actual = sutProvider.Sut.Create([]); - - Assert.True(actual.CanBeRestored(twoFactorEnabled, organizationId)); - } - - [Theory] - [BitAutoData(OrganizationUserStatusType.Revoked)] - [BitAutoData(OrganizationUserStatusType.Invited)] - [BitAutoData(OrganizationUserStatusType.Accepted)] - [BitAutoData(OrganizationUserStatusType.Confirmed)] - public void CanBeRestored_WithTwoFactorEnabled_ReturnsTrue( - OrganizationUserStatusType userStatus, Guid organizationId, - SutProvider sutProvider) - { - var actual = sutProvider.Sut.Create( - [ - new PolicyDetails - { - OrganizationId = organizationId, - PolicyType = PolicyType.TwoFactorAuthentication, - OrganizationUserStatus = userStatus - } - ]); - - Assert.True(actual.CanBeRestored(true, organizationId)); - } - - [Theory] - [BitAutoData(OrganizationUserStatusType.Revoked)] - [BitAutoData(OrganizationUserStatusType.Invited)] - [BitAutoData(OrganizationUserStatusType.Accepted)] - [BitAutoData(OrganizationUserStatusType.Confirmed)] - public void CanBeRestored_WithAnyStatus_ReturnsFalse( - OrganizationUserStatusType userStatus, Guid organizationId, - SutProvider sutProvider) - { - var actual = sutProvider.Sut.Create( - [ - new PolicyDetails - { - OrganizationId = organizationId, - PolicyType = PolicyType.TwoFactorAuthentication, - OrganizationUserStatus = userStatus - } - ]); - - Assert.False(actual.CanBeRestored(false, organizationId)); + Assert.False(actual.IsTwoFactorRequiredForOrganization(organizationId)); } [Theory, BitAutoData]