1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-12 06:00:36 -05:00

Refactor RequireTwoFactorPolicyRequirement to return tuples of (OrganizationId, OrganizationUserId) for active memberships requiring two-factor authentication. Update UserService and related tests to reflect this change.

This commit is contained in:
Rui Tome 2025-05-23 14:19:11 +01:00
parent 705bccae10
commit 2e3056fc2a
No known key found for this signature in database
GPG Key ID: 526239D96A8EC066
3 changed files with 25 additions and 18 deletions

View File

@ -28,13 +28,15 @@ public class RequireTwoFactorPolicyRequirement : IPolicyRequirement
_policyDetails.Any(p => p.OrganizationId == organizationId);
/// <summary>
/// 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.
/// </summary>
/// <returns>The active two-factor authentication policies for active memberships.</returns>
public IEnumerable<PolicyDetails> 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<RequireTwoFactorPolicyRequirement>

View File

@ -1403,13 +1403,13 @@ public class UserService : UserManager<User>, IUserService, IDisposable
{
var requirement = await _policyRequirementQuery.GetAsync<RequireTwoFactorPolicyRequirement>(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();

View File

@ -59,17 +59,18 @@ public class RequireTwoFactorPolicyRequirementFactoryTests
}
[Theory, BitAutoData]
public void TwoFactorPoliciesForActiveMemberships_WithNoPolicies_ReturnsEmptyCollection(
public void OrganizationsRequiringTwoFactor_WithNoPolicies_ReturnsEmptyCollection(
SutProvider<RequireTwoFactorPolicyRequirementFactory> 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<RequireTwoFactorPolicyRequirementFactory> 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);
}
}