mirror of
https://github.com/bitwarden/server
synced 2025-12-16 00:03:54 +00:00
[PM-22241] Add DefaultUserCollectionName support to bulk organization user confirmation (#6153)
* Implement GetByOrganizationAsync method in PolicyRequirementQuery and add corresponding unit tests * Refactor ConfirmOrganizationUserCommand for clarity and add bulk support * Update ConfirmOrganizationUserCommandTests to use GetByOrganizationAsync for policy requirement queries * Add DefaultUserCollectionName property to OrganizationUserBulkConfirmRequestModel with encryption attributes * Update ConfirmUsersAsync method to include DefaultUserCollectionName parameter in OrganizationUsersController * Add EnableOrganizationDataOwnershipPolicyAsync method to OrganizationTestHelpers * Add integration tests for confirming organization users in OrganizationUserControllerTests - Implemented Confirm_WithValidUser test to verify successful confirmation of a single user. - Added BulkConfirm_WithValidUsers test to ensure multiple users can be confirmed successfully. * Refactor organization user confirmation integration tests to also test when the organization data ownership policy is disabled * Refactor ConfirmOrganizationUserCommand to consolidate confirmation side effects handling - Replaced single and bulk confirmation side effect methods with a unified HandleConfirmationSideEffectsAsync method. - Updated related logic to handle confirmed organization users more efficiently. - Adjusted unit tests to reflect changes in the collection creation process for confirmed users. * Refactor OrganizationUserControllerTests to simplify feature flag handling and consolidate test logic - Removed redundant feature flag checks in Confirm and BulkConfirm tests. - Updated tests to directly enable the Organization Data Ownership policy without conditional checks. - Ensured verification of DefaultUserCollection for confirmed users remains intact. * Refactor OrganizationUserControllerTests to enhance clarity and reduce redundancy - Simplified user creation and confirmation logic in tests by introducing helper methods. - Consolidated verification of confirmed users and their associated collections. - Removed unnecessary comments and streamlined test flow for better readability.
This commit is contained in:
@@ -11,7 +11,6 @@ using Bit.Core.Billing.Enums;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Platform.Push;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
@@ -67,7 +66,7 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
|
||||
public async Task<OrganizationUser> ConfirmUserAsync(Guid organizationId, Guid organizationUserId, string key,
|
||||
Guid confirmingUserId, string defaultUserCollectionName = null)
|
||||
{
|
||||
var result = await ConfirmUsersAsync(
|
||||
var result = await SaveChangesToDatabaseAsync(
|
||||
organizationId,
|
||||
new Dictionary<Guid, string>() { { organizationUserId, key } },
|
||||
confirmingUserId);
|
||||
@@ -83,12 +82,30 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
|
||||
throw new BadRequestException(error);
|
||||
}
|
||||
|
||||
await HandleConfirmationSideEffectsAsync(organizationId, orgUser, defaultUserCollectionName);
|
||||
await HandleConfirmationSideEffectsAsync(organizationId, confirmedOrganizationUsers: [orgUser], defaultUserCollectionName);
|
||||
|
||||
return orgUser;
|
||||
}
|
||||
|
||||
public async Task<List<Tuple<OrganizationUser, string>>> ConfirmUsersAsync(Guid organizationId, Dictionary<Guid, string> keys,
|
||||
Guid confirmingUserId, string defaultUserCollectionName = null)
|
||||
{
|
||||
var result = await SaveChangesToDatabaseAsync(organizationId, keys, confirmingUserId);
|
||||
|
||||
var confirmedOrganizationUsers = result
|
||||
.Where(r => string.IsNullOrEmpty(r.Item2))
|
||||
.Select(r => r.Item1)
|
||||
.ToList();
|
||||
|
||||
if (confirmedOrganizationUsers.Count > 0)
|
||||
{
|
||||
await HandleConfirmationSideEffectsAsync(organizationId, confirmedOrganizationUsers, defaultUserCollectionName);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<List<Tuple<OrganizationUser, string>>> SaveChangesToDatabaseAsync(Guid organizationId, Dictionary<Guid, string> keys,
|
||||
Guid confirmingUserId)
|
||||
{
|
||||
var selectedOrganizationUsers = await _organizationUserRepository.GetManyAsync(keys.Keys);
|
||||
@@ -227,17 +244,7 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
|
||||
.Select(d => d.Id.ToString());
|
||||
}
|
||||
|
||||
private async Task HandleConfirmationSideEffectsAsync(Guid organizationId, OrganizationUser organizationUser, string defaultUserCollectionName)
|
||||
{
|
||||
// Create DefaultUserCollection type collection for the user if the OrganizationDataOwnership policy is enabled for the organization
|
||||
var requiresDefaultCollection = await OrganizationRequiresDefaultCollectionAsync(organizationId, organizationUser.UserId.Value, defaultUserCollectionName);
|
||||
if (requiresDefaultCollection)
|
||||
{
|
||||
await CreateDefaultCollectionAsync(organizationId, organizationUser.Id, defaultUserCollectionName);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> OrganizationRequiresDefaultCollectionAsync(Guid organizationId, Guid userId, string defaultUserCollectionName)
|
||||
private async Task<bool> OrganizationRequiresDefaultCollectionAsync(Guid organizationId, string defaultUserCollectionName)
|
||||
{
|
||||
if (!_featureService.IsEnabled(FeatureFlagKeys.CreateDefaultLocation))
|
||||
{
|
||||
@@ -250,30 +257,29 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
|
||||
return false;
|
||||
}
|
||||
|
||||
var organizationDataOwnershipRequirement = await _policyRequirementQuery.GetAsync<OrganizationDataOwnershipPolicyRequirement>(userId);
|
||||
return organizationDataOwnershipRequirement.RequiresDefaultCollection(organizationId);
|
||||
var organizationPolicyRequirement = await _policyRequirementQuery.GetByOrganizationAsync<OrganizationDataOwnershipPolicyRequirement>(organizationId);
|
||||
|
||||
// Check if the organization requires default collections
|
||||
return organizationPolicyRequirement.RequiresDefaultCollection(organizationId);
|
||||
}
|
||||
|
||||
private async Task CreateDefaultCollectionAsync(Guid organizationId, Guid organizationUserId, string defaultCollectionName)
|
||||
/// <summary>
|
||||
/// Handles the side effects of confirming an organization user.
|
||||
/// Creates a default collection for the user if the organization
|
||||
/// has the OrganizationDataOwnership policy enabled.
|
||||
/// </summary>
|
||||
/// <param name="organizationId">The organization ID.</param>
|
||||
/// <param name="confirmedOrganizationUsers">The confirmed organization users.</param>
|
||||
/// <param name="defaultUserCollectionName">The encrypted default user collection name.</param>
|
||||
private async Task HandleConfirmationSideEffectsAsync(Guid organizationId, IEnumerable<OrganizationUser> confirmedOrganizationUsers, string defaultUserCollectionName)
|
||||
{
|
||||
var collection = new Collection
|
||||
var requiresDefaultCollections = await OrganizationRequiresDefaultCollectionAsync(organizationId, defaultUserCollectionName);
|
||||
if (!requiresDefaultCollections)
|
||||
{
|
||||
OrganizationId = organizationId,
|
||||
Name = defaultCollectionName,
|
||||
Type = CollectionType.DefaultUserCollection
|
||||
};
|
||||
return;
|
||||
}
|
||||
|
||||
var userAccess = new List<CollectionAccessSelection>
|
||||
{
|
||||
new CollectionAccessSelection
|
||||
{
|
||||
Id = organizationUserId,
|
||||
ReadOnly = false,
|
||||
HidePasswords = false,
|
||||
Manage = true
|
||||
}
|
||||
};
|
||||
|
||||
await _collectionRepository.CreateAsync(collection, groups: null, users: userAccess);
|
||||
var organizationUserIds = confirmedOrganizationUsers.Select(u => u.Id).ToList();
|
||||
await _collectionRepository.CreateDefaultCollectionsAsync(organizationId, organizationUserIds, defaultUserCollectionName);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user