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]