1
0
mirror of https://github.com/bitwarden/server synced 2025-12-17 08:43:27 +00:00

added auto confirm restriction on top of single org.

This commit is contained in:
jrmccannon
2025-11-25 15:21:18 -06:00
parent 6e317e9799
commit d38e2c3859
3 changed files with 50 additions and 22 deletions

View File

@@ -418,12 +418,15 @@ public class ProviderService : IProviderService
"The organization is subscribed to Secrets Manager. Please contact Customer Support to manage the subscription."); "The organization is subscribed to Secrets Manager. Please contact Customer Support to manage the subscription.");
} }
var organizationAutoConfirmPolicyRequirement = await _policyRequirementQuery if (_featureService.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers))
.GetManyByOrganizationIdAsync<AutomaticUserConfirmationPolicyRequirement>(organizationId);
if (organizationAutoConfirmPolicyRequirement.Any())
{ {
throw new BadRequestException(new AutoConfirmDoesNotAllowProviderUsers().Message); var organizationAutoConfirmPolicyRequirement = await _policyRequirementQuery
.GetManyByOrganizationIdAsync<AutomaticUserConfirmationPolicyRequirement>(organizationId);
if (organizationAutoConfirmPolicyRequirement.Any())
{
throw new BadRequestException(new AutoConfirmDoesNotAllowProviderUsers().Message);
}
} }
var providerOrganization = new ProviderOrganization var providerOrganization = new ProviderOrganization

View File

@@ -1,6 +1,7 @@
using Bit.Core.AdminConsole.Enums; using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccount; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.DeleteClaimedAccount;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies; using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Enforcement.AutoConfirm;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements; using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
using Bit.Core.AdminConsole.Repositories; using Bit.Core.AdminConsole.Repositories;
using Bit.Core.AdminConsole.Utilities.v2; using Bit.Core.AdminConsole.Utilities.v2;
@@ -8,6 +9,7 @@ using Bit.Core.AdminConsole.Utilities.v2.Validation;
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces; using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Repositories; using Bit.Core.Repositories;
using Bit.Core.Services;
using static Bit.Core.AdminConsole.Utilities.v2.Validation.ValidationResultHelpers; using static Bit.Core.AdminConsole.Utilities.v2.Validation.ValidationResultHelpers;
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.AutoConfirmUser; namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.AutoConfirmUser;
@@ -16,6 +18,8 @@ public class AutomaticallyConfirmOrganizationUsersValidator(
IOrganizationUserRepository organizationUserRepository, IOrganizationUserRepository organizationUserRepository,
ITwoFactorIsEnabledQuery twoFactorIsEnabledQuery, ITwoFactorIsEnabledQuery twoFactorIsEnabledQuery,
IPolicyRequirementQuery policyRequirementQuery, IPolicyRequirementQuery policyRequirementQuery,
IAutomaticUserConfirmationPolicyEnforcementQuery automaticUserConfirmationPolicyEnforcementQuery,
IUserService userService,
IPolicyRepository policyRepository) : IAutomaticallyConfirmOrganizationUsersValidator IPolicyRepository policyRepository) : IAutomaticallyConfirmOrganizationUsersValidator
{ {
public async Task<ValidationResult<AutomaticallyConfirmOrganizationUserValidationRequest>> ValidateAsync( public async Task<ValidationResult<AutomaticallyConfirmOrganizationUserValidationRequest>> ValidateAsync(
@@ -61,7 +65,7 @@ public class AutomaticallyConfirmOrganizationUsersValidator(
return Invalid(request, new UserDoesNotHaveTwoFactorEnabled()); return Invalid(request, new UserDoesNotHaveTwoFactorEnabled());
} }
if (await OrganizationUserConformsToSingleOrgPolicyAsync(request) is { } error) if (await OrganizationUserConformsToAutomaticUserConfirmationPolicyAsync(request) is { } error)
{ {
return Invalid(request, error); return Invalid(request, error);
} }
@@ -87,30 +91,27 @@ public class AutomaticallyConfirmOrganizationUsersValidator(
.IsTwoFactorRequiredForOrganization(request.Organization!.Id); .IsTwoFactorRequiredForOrganization(request.Organization!.Id);
} }
private async Task<Error?> OrganizationUserConformsToSingleOrgPolicyAsync( private async Task<Error?> OrganizationUserConformsToAutomaticUserConfirmationPolicyAsync(
AutomaticallyConfirmOrganizationUserValidationRequest request) AutomaticallyConfirmOrganizationUserValidationRequest request)
{ {
var allOrganizationUsersForUser = await organizationUserRepository var allOrganizationUsersForUser = await organizationUserRepository
.GetManyByUserAsync(request.OrganizationUser!.UserId!.Value); .GetManyByUserAsync(request.OrganizationUser!.UserId!.Value);
var user = await userService.GetUserByIdAsync(request.OrganizationUser!.UserId!.Value);
if (allOrganizationUsersForUser.Count == 1) if (allOrganizationUsersForUser.Count == 1)
{ {
return null; return null;
} }
var policyRequirement = await policyRequirementQuery return (await automaticUserConfirmationPolicyEnforcementQuery.IsCompliantAsync(
.GetAsync<SingleOrganizationPolicyRequirement>(request.OrganizationUser!.UserId!.Value); new AutomaticUserConfirmationPolicyEnforcementRequest(
request.OrganizationUser,
if (policyRequirement.IsSingleOrgEnabledForThisOrganization(request.Organization!.Id)) allOrganizationUsersForUser.Where(x => x.OrganizationId != request.OrganizationId),
{ user)))
return new OrganizationEnforcesSingleOrgPolicy(); .Match<Error?>(
} error => error,
_ => null
if (policyRequirement.IsSingleOrgEnabledForOrganizationsOtherThan(request.Organization.Id)) );
{
return new OtherOrganizationEnforcesSingleOrgPolicy();
}
return null;
} }
} }

View File

@@ -4,6 +4,7 @@
using Bit.Core.AdminConsole.Enums; using Bit.Core.AdminConsole.Enums;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces; using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies; using Bit.Core.AdminConsole.OrganizationFeatures.Policies;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.Enforcement.AutoConfirm;
using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements; using Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyRequirements;
using Bit.Core.AdminConsole.Services; using Bit.Core.AdminConsole.Services;
using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces; using Bit.Core.Auth.UserFeatures.TwoFactorAuth.Interfaces;
@@ -33,6 +34,7 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
private readonly IPolicyRequirementQuery _policyRequirementQuery; private readonly IPolicyRequirementQuery _policyRequirementQuery;
private readonly IFeatureService _featureService; private readonly IFeatureService _featureService;
private readonly ICollectionRepository _collectionRepository; private readonly ICollectionRepository _collectionRepository;
private readonly IAutomaticUserConfirmationPolicyEnforcementQuery _automaticUserConfirmationPolicyEnforcementQuery;
public ConfirmOrganizationUserCommand( public ConfirmOrganizationUserCommand(
IOrganizationRepository organizationRepository, IOrganizationRepository organizationRepository,
@@ -47,7 +49,8 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
IDeviceRepository deviceRepository, IDeviceRepository deviceRepository,
IPolicyRequirementQuery policyRequirementQuery, IPolicyRequirementQuery policyRequirementQuery,
IFeatureService featureService, IFeatureService featureService,
ICollectionRepository collectionRepository) ICollectionRepository collectionRepository,
IAutomaticUserConfirmationPolicyEnforcementQuery automaticUserConfirmationPolicyEnforcementQuery)
{ {
_organizationRepository = organizationRepository; _organizationRepository = organizationRepository;
_organizationUserRepository = organizationUserRepository; _organizationUserRepository = organizationUserRepository;
@@ -62,6 +65,7 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
_policyRequirementQuery = policyRequirementQuery; _policyRequirementQuery = policyRequirementQuery;
_featureService = featureService; _featureService = featureService;
_collectionRepository = collectionRepository; _collectionRepository = collectionRepository;
_automaticUserConfirmationPolicyEnforcementQuery = automaticUserConfirmationPolicyEnforcementQuery;
} }
public async Task<OrganizationUser> ConfirmUserAsync(Guid organizationId, Guid organizationUserId, string key, public async Task<OrganizationUser> ConfirmUserAsync(Guid organizationId, Guid organizationUserId, string key,
@@ -127,6 +131,7 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
var organization = await _organizationRepository.GetByIdAsync(organizationId); var organization = await _organizationRepository.GetByIdAsync(organizationId);
var allUsersOrgs = await _organizationUserRepository.GetManyByManyUsersAsync(validSelectedUserIds); var allUsersOrgs = await _organizationUserRepository.GetManyByManyUsersAsync(validSelectedUserIds);
var users = await _userRepository.GetManyAsync(validSelectedUserIds); var users = await _userRepository.GetManyAsync(validSelectedUserIds);
var usersTwoFactorEnabled = await _twoFactorIsEnabledQuery.TwoFactorIsEnabledAsync(validSelectedUserIds); var usersTwoFactorEnabled = await _twoFactorIsEnabledQuery.TwoFactorIsEnabledAsync(validSelectedUserIds);
@@ -188,6 +193,25 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
await ValidateTwoFactorAuthenticationPolicyAsync(user, organizationId, userTwoFactorEnabled); await ValidateTwoFactorAuthenticationPolicyAsync(user, organizationId, userTwoFactorEnabled);
var hasOtherOrgs = userOrgs.Any(ou => ou.OrganizationId != organizationId); var hasOtherOrgs = userOrgs.Any(ou => ou.OrganizationId != organizationId);
if (_featureService.IsEnabled(FeatureFlagKeys.AutomaticConfirmUsers))
{
var error = (await _automaticUserConfirmationPolicyEnforcementQuery.IsCompliantAsync(
new AutomaticUserConfirmationPolicyEnforcementRequest(
userOrgs.First(x => x.OrganizationId == organizationId),
userOrgs.Where(x => x.OrganizationId != organizationId),
user)))
.Match(
error => error.Message,
_ => string.Empty
);
if (!string.IsNullOrEmpty(error))
{
throw new BadRequestException(error);
}
}
var singleOrgPolicies = await _policyService.GetPoliciesApplicableToUserAsync(user.Id, PolicyType.SingleOrg); var singleOrgPolicies = await _policyService.GetPoliciesApplicableToUserAsync(user.Id, PolicyType.SingleOrg);
var otherSingleOrgPolicies = var otherSingleOrgPolicies =
singleOrgPolicies.Where(p => p.OrganizationId != organizationId); singleOrgPolicies.Where(p => p.OrganizationId != organizationId);