1
0
mirror of https://github.com/bitwarden/server.git synced 2025-05-22 12:04:27 -05:00

Enhance ConfirmOrganizationUserCommand to validate two-factor authentication policy based on feature flag; refactor validation logic and update related tests for improved policy handling.

This commit is contained in:
Rui Tome 2025-05-20 16:51:15 +01:00
parent 02cbdd64a4
commit ec81ed786a
No known key found for this signature in database
GPG Key ID: 526239D96A8EC066
2 changed files with 53 additions and 18 deletions

View File

@ -152,7 +152,19 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
ICollection<OrganizationUser> userOrgs, bool userTwoFactorEnabled)
{
// Enforce Two Factor Authentication Policy for this organization
await CheckTwoFactorPolicyAsync(organizationId, user, userTwoFactorEnabled);
if (_featureService.IsEnabled(FeatureFlagKeys.PolicyRequirements))
{
await ValidateTwoFactorAuthenticationPolicyAsync(user, organizationId, userTwoFactorEnabled);
}
else
{
var orgRequiresTwoFactor = (await _policyService.GetPoliciesApplicableToUserAsync(user.Id, PolicyType.TwoFactorAuthentication))
.Any(p => p.OrganizationId == organizationId);
if (orgRequiresTwoFactor && !userTwoFactorEnabled)
{
throw new BadRequestException("User does not have two-step login enabled.");
}
}
var hasOtherOrgs = userOrgs.Any(ou => ou.OrganizationId != organizationId);
var singleOrgPolicies = await _policyService.GetPoliciesApplicableToUserAsync(user.Id, PolicyType.SingleOrg);
@ -170,27 +182,25 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
}
}
private async Task CheckTwoFactorPolicyAsync(Guid organizationId, User user, bool userTwoFactorEnabled)
/// <summary>
/// Validates the two-factor authentication policy for the organization user.
/// If the user has two-step login enabled, the policy is not enforced.
/// </summary>
/// <param name="user">The user to validate the policy for.</param>
/// <param name="organizationId">The ID of the organization to validate the policy for.</param>
/// <param name="userTwoFactorEnabled">Whether the user has two-step login enabled.</param>
private async Task ValidateTwoFactorAuthenticationPolicyAsync(User user, Guid organizationId, bool userTwoFactorEnabled)
{
if (userTwoFactorEnabled)
{
// If the user has two-step login enabled, the policy is not enforced.
return;
}
bool requireTwoFactor;
var requirement = await _policyRequirementQuery.GetAsync<RequireTwoFactorPolicyRequirement>(user.Id);
var canBeConfirmed = requirement.CanBeConfirmed(userTwoFactorEnabled, organizationId);
if (_featureService.IsEnabled(FeatureFlagKeys.PolicyRequirements))
{
var requirement = await _policyRequirementQuery.GetAsync<RequireTwoFactorPolicyRequirement>(user.Id);
requireTwoFactor = requirement.RequireTwoFactor;
}
else
{
requireTwoFactor = (await _policyService.GetPoliciesApplicableToUserAsync(user.Id, PolicyType.TwoFactorAuthentication))
.Any(p => p.OrganizationId == organizationId);
}
if (requireTwoFactor)
if (!canBeConfirmed)
{
throw new BadRequestException("User does not have two-step login enabled.");
}

View File

@ -1,5 +1,6 @@
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.Models.Data.Organizations.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.Services;
@ -344,7 +345,15 @@ public class ConfirmOrganizationUserCommandTests
userRepository.GetManyAsync(default).ReturnsForAnyArgs(new[] { user });
featureService.IsEnabled(FeatureFlagKeys.PolicyRequirements).Returns(true);
policyRequirementQuery.GetAsync<RequireTwoFactorPolicyRequirement>(user.Id)
.Returns(new RequireTwoFactorPolicyRequirement { RequireTwoFactor = true });
.Returns(new RequireTwoFactorPolicyRequirement(
[
new PolicyDetails
{
OrganizationId = org.Id,
OrganizationUserStatus = OrganizationUserStatusType.Accepted,
PolicyType = PolicyType.TwoFactorAuthentication
}
]));
twoFactorIsEnabledQuery.TwoFactorIsEnabledAsync(Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(user.Id)))
.Returns(new List<(Guid userId, bool twoFactorIsEnabled)>() { (user.Id, false) });
@ -374,7 +383,15 @@ public class ConfirmOrganizationUserCommandTests
userRepository.GetManyAsync(default).ReturnsForAnyArgs(new[] { user });
featureService.IsEnabled(FeatureFlagKeys.PolicyRequirements).Returns(true);
policyRequirementQuery.GetAsync<RequireTwoFactorPolicyRequirement>(user.Id)
.Returns(new RequireTwoFactorPolicyRequirement { RequireTwoFactor = false });
.Returns(new RequireTwoFactorPolicyRequirement(
[
new PolicyDetails
{
OrganizationId = Guid.NewGuid(),
OrganizationUserStatus = OrganizationUserStatusType.Invited,
PolicyType = PolicyType.TwoFactorAuthentication,
}
]));
twoFactorIsEnabledQuery.TwoFactorIsEnabledAsync(Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(user.Id)))
.Returns(new List<(Guid userId, bool twoFactorIsEnabled)>() { (user.Id, false) });
@ -406,7 +423,15 @@ public class ConfirmOrganizationUserCommandTests
userRepository.GetManyAsync(default).ReturnsForAnyArgs(new[] { user });
featureService.IsEnabled(FeatureFlagKeys.PolicyRequirements).Returns(true);
policyRequirementQuery.GetAsync<RequireTwoFactorPolicyRequirement>(user.Id)
.Returns(new RequireTwoFactorPolicyRequirement { RequireTwoFactor = true });
.Returns(new RequireTwoFactorPolicyRequirement(
[
new PolicyDetails
{
OrganizationId = org.Id,
OrganizationUserStatus = OrganizationUserStatusType.Accepted,
PolicyType = PolicyType.TwoFactorAuthentication
}
]));
twoFactorIsEnabledQuery.TwoFactorIsEnabledAsync(Arg.Is<IEnumerable<Guid>>(ids => ids.Contains(user.Id)))
.Returns(new List<(Guid userId, bool twoFactorIsEnabled)>() { (user.Id, true) });