1
0
mirror of https://github.com/bitwarden/server synced 2025-12-25 12:43:14 +00:00

[PM-20140] Prevent accidental bulk removal of users without a Master Password (#6173)

This commit is contained in:
Thomas Rittson
2025-08-12 10:21:29 +10:00
committed by GitHub
parent 3c5de319d1
commit 9022ad2360
6 changed files with 118 additions and 31 deletions

View File

@@ -1,12 +1,7 @@
#nullable enable
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Models.Business;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
using Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.InviteUsers;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Billing.Pricing;
using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
@@ -17,7 +12,7 @@ using Bit.Core.Models.Data.Organizations.OrganizationUsers;
using Bit.Core.Repositories;
using Bit.Core.Services;
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers;
namespace Bit.Core.AdminConsole.OrganizationFeatures.Import;
public class ImportOrganizationUsersAndGroupsCommand : IImportOrganizationUsersAndGroupsCommand
{
@@ -26,10 +21,8 @@ public class ImportOrganizationUsersAndGroupsCommand : IImportOrganizationUsersA
private readonly IPaymentService _paymentService;
private readonly IGroupRepository _groupRepository;
private readonly IEventService _eventService;
private readonly ICurrentContext _currentContext;
private readonly IOrganizationService _organizationService;
private readonly IInviteOrganizationUsersCommand _inviteOrganizationUsersCommand;
private readonly IPricingClient _pricingClient;
private readonly IFeatureService _featureService;
private readonly EventSystemUser _EventSystemUser = EventSystemUser.PublicApi;
@@ -38,21 +31,16 @@ public class ImportOrganizationUsersAndGroupsCommand : IImportOrganizationUsersA
IPaymentService paymentService,
IGroupRepository groupRepository,
IEventService eventService,
ICurrentContext currentContext,
IOrganizationService organizationService,
IInviteOrganizationUsersCommand inviteOrganizationUsersCommand,
IPricingClient pricingClient
)
IFeatureService featureService)
{
_organizationRepository = organizationRepository;
_organizationUserRepository = organizationUserRepository;
_paymentService = paymentService;
_groupRepository = groupRepository;
_eventService = eventService;
_currentContext = currentContext;
_organizationService = organizationService;
_inviteOrganizationUsersCommand = inviteOrganizationUsersCommand;
_pricingClient = pricingClient;
_featureService = featureService;
}
/// <summary>
@@ -243,10 +231,23 @@ public class ImportOrganizationUsersAndGroupsCommand : IImportOrganizationUsersA
List<(OrganizationUserUserDetails ou, EventType e, DateTime? d)> events,
OrganizationUserImportData importUserData)
{
var usersToDelete = importUserData.ExistingExternalUsers.Where(u =>
u.Type != OrganizationUserType.Owner &&
!importUserData.ImportedExternalIds.Contains(u.ExternalId) &&
importUserData.ExistingExternalUsersIdDict.ContainsKey(u.ExternalId));
var usersToDelete = importUserData.ExistingExternalUsers
.Where(u =>
u.Type != OrganizationUserType.Owner &&
!importUserData.ImportedExternalIds.Contains(u.ExternalId) &&
importUserData.ExistingExternalUsersIdDict.ContainsKey(u.ExternalId))
.ToList();
if (_featureService.IsEnabled(FeatureFlagKeys.DirectoryConnectorPreventUserRemoval) &&
usersToDelete.Any(u => !u.HasMasterPassword))
{
// Removing users without an MP will put their account in an unrecoverable state.
// We allow this during normal syncs for offboarding, but overwriteExisting risks bricking every user in
// the organization, so you don't get to do it here.
throw new BadRequestException(
"Sync failed. To proceed, disable the 'Remove and re-add users during next sync' setting and try again.");
}
await _organizationUserRepository.DeleteManyAsync(usersToDelete.Select(u => u.Id));
events.AddRange(usersToDelete.Select(u => (
u,