diff --git a/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyRequirements/RequireTwoFactorPolicyRequirement.cs b/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyRequirements/RequireTwoFactorPolicyRequirement.cs index 9bad7b6dcc..5bc642fdcb 100644 --- a/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyRequirements/RequireTwoFactorPolicyRequirement.cs +++ b/src/Core/AdminConsole/OrganizationFeatures/Policies/PolicyRequirements/RequireTwoFactorPolicyRequirement.cs @@ -28,13 +28,15 @@ public class RequireTwoFactorPolicyRequirement : IPolicyRequirement _policyDetails.Any(p => p.OrganizationId == organizationId); /// - /// Gets the active two-factor authentication policies for active memberships. + /// Returns tuples of (OrganizationId, OrganizationUserId) for active memberships where two-factor authentication is required. + /// Users should be revoked from these organizations if they disable all 2FA methods. /// - /// The active two-factor authentication policies for active memberships. - public IEnumerable TwoFactorPoliciesForActiveMemberships => - _policyDetails.Where(p => p.OrganizationUserStatus is + public IEnumerable<(Guid OrganizationId, Guid OrganizationUserId)> OrganizationsRequiringTwoFactor => + _policyDetails + .Where(p => p.OrganizationUserStatus is OrganizationUserStatusType.Accepted or - OrganizationUserStatusType.Confirmed); + OrganizationUserStatusType.Confirmed) + .Select(p => (p.OrganizationId, p.OrganizationUserId)); } public class RequireTwoFactorPolicyRequirementFactory : BasePolicyRequirementFactory diff --git a/src/Core/Services/Implementations/UserService.cs b/src/Core/Services/Implementations/UserService.cs index b1e7159b7c..59a758ac64 100644 --- a/src/Core/Services/Implementations/UserService.cs +++ b/src/Core/Services/Implementations/UserService.cs @@ -1403,13 +1403,13 @@ public class UserService : UserManager, IUserService, IDisposable { var requirement = await _policyRequirementQuery.GetAsync(user.Id); - var removeOrgUserTasks = requirement.TwoFactorPoliciesForActiveMemberships.Select(async p => + var removeOrgUserTasks = requirement.OrganizationsRequiringTwoFactor.Select(async o => { - var organization = await _organizationRepository.GetByIdAsync(p.OrganizationId); + var organization = await _organizationRepository.GetByIdAsync(o.OrganizationId); await _revokeNonCompliantOrganizationUserCommand.RevokeNonCompliantOrganizationUsersAsync( new RevokeOrganizationUsersRequest( - p.OrganizationId, - [new OrganizationUserUserDetails { Id = p.OrganizationUserId, OrganizationId = p.OrganizationId }], + o.OrganizationId, + [new OrganizationUserUserDetails { Id = o.OrganizationUserId, OrganizationId = o.OrganizationId }], new SystemUser(EventSystemUser.TwoFactorDisabled))); await _mailService.SendOrganizationUserRevokedForTwoFactorPolicyEmailAsync(organization.DisplayName(), user.Email); }).ToArray(); diff --git a/test/Core.Test/AdminConsole/OrganizationFeatures/Policies/PolicyRequirements/RequireTwoFactorPolicyRequirementFactoryTests.cs b/test/Core.Test/AdminConsole/OrganizationFeatures/Policies/PolicyRequirements/RequireTwoFactorPolicyRequirementFactoryTests.cs index e03d1a564c..c20ea494ab 100644 --- a/test/Core.Test/AdminConsole/OrganizationFeatures/Policies/PolicyRequirements/RequireTwoFactorPolicyRequirementFactoryTests.cs +++ b/test/Core.Test/AdminConsole/OrganizationFeatures/Policies/PolicyRequirements/RequireTwoFactorPolicyRequirementFactoryTests.cs @@ -59,17 +59,18 @@ public class RequireTwoFactorPolicyRequirementFactoryTests } [Theory, BitAutoData] - public void TwoFactorPoliciesForActiveMemberships_WithNoPolicies_ReturnsEmptyCollection( + public void OrganizationsRequiringTwoFactor_WithNoPolicies_ReturnsEmptyCollection( SutProvider sutProvider) { var actual = sutProvider.Sut.Create([]); - Assert.Empty(actual.TwoFactorPoliciesForActiveMemberships); + Assert.Empty(actual.OrganizationsRequiringTwoFactor); } [Theory, BitAutoData] - public void TwoFactorPoliciesForActiveMemberships_WithMultiplePolicies_ReturnsActiveMemberships( - Guid orgId1, Guid orgId2, Guid orgId3, Guid orgId4, + public void OrganizationsRequiringTwoFactor_WithMultiplePolicies_ReturnsActiveMemberships( + Guid orgId1, Guid orgUserId1, Guid orgId2, Guid orgUserId2, + Guid orgId3, Guid orgUserId3, Guid orgId4, Guid orgUserId4, SutProvider sutProvider) { var policies = new[] @@ -77,24 +78,28 @@ public class RequireTwoFactorPolicyRequirementFactoryTests new PolicyDetails { OrganizationId = orgId1, + OrganizationUserId = orgUserId1, PolicyType = PolicyType.TwoFactorAuthentication, OrganizationUserStatus = OrganizationUserStatusType.Accepted }, new PolicyDetails { OrganizationId = orgId2, + OrganizationUserId = orgUserId2, PolicyType = PolicyType.TwoFactorAuthentication, OrganizationUserStatus = OrganizationUserStatusType.Confirmed }, new PolicyDetails { OrganizationId = orgId3, + OrganizationUserId = orgUserId3, PolicyType = PolicyType.TwoFactorAuthentication, OrganizationUserStatus = OrganizationUserStatusType.Invited }, new PolicyDetails { OrganizationId = orgId4, + OrganizationUserId = orgUserId4, PolicyType = PolicyType.TwoFactorAuthentication, OrganizationUserStatus = OrganizationUserStatusType.Revoked } @@ -102,11 +107,11 @@ public class RequireTwoFactorPolicyRequirementFactoryTests var actual = sutProvider.Sut.Create(policies); - var result = actual.TwoFactorPoliciesForActiveMemberships.ToList(); + var result = actual.OrganizationsRequiringTwoFactor.ToList(); Assert.Equal(2, result.Count); - Assert.Contains(result, p => p.OrganizationId == orgId1); - Assert.Contains(result, p => p.OrganizationId == orgId2); - Assert.DoesNotContain(result, p => p.OrganizationId == orgId3); - Assert.DoesNotContain(result, p => p.OrganizationId == orgId4); + Assert.Contains(result, p => p.OrganizationId == orgId1 && p.OrganizationUserId == orgUserId1); + Assert.Contains(result, p => p.OrganizationId == orgId2 && p.OrganizationUserId == orgUserId2); + Assert.DoesNotContain(result, p => p.OrganizationId == orgId3 && p.OrganizationUserId == orgUserId3); + Assert.DoesNotContain(result, p => p.OrganizationId == orgId4 && p.OrganizationUserId == orgUserId4); } }