mirror of
https://github.com/bitwarden/server
synced 2026-01-03 17:14:00 +00:00
[PM-24582] Bugfix: exclude admins and owners from default user collection creation on confirmation (#6177)
* Update the OrganizationUserController integration Confirm tests to handle the Owner type * Refactor ConfirmOrganizationUserCommand to simplify side-effect handling in organization user confirmation. Update IPolicyRequirementQuery to return eligible org user IDs for policy enforcement. Update tests for method signature changes and default collection creation logic.
This commit is contained in:
@@ -244,25 +244,6 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
|
||||
.Select(d => d.Id.ToString());
|
||||
}
|
||||
|
||||
private async Task<bool> OrganizationRequiresDefaultCollectionAsync(Guid organizationId, string defaultUserCollectionName)
|
||||
{
|
||||
if (!_featureService.IsEnabled(FeatureFlagKeys.CreateDefaultLocation))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Skip if no collection name provided (backwards compatibility)
|
||||
if (string.IsNullOrWhiteSpace(defaultUserCollectionName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var organizationPolicyRequirement = await _policyRequirementQuery.GetByOrganizationAsync<OrganizationDataOwnershipPolicyRequirement>(organizationId);
|
||||
|
||||
// Check if the organization requires default collections
|
||||
return organizationPolicyRequirement.RequiresDefaultCollection(organizationId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the side effects of confirming an organization user.
|
||||
/// Creates a default collection for the user if the organization
|
||||
@@ -271,15 +252,32 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
|
||||
/// <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)
|
||||
private async Task HandleConfirmationSideEffectsAsync(Guid organizationId,
|
||||
IEnumerable<OrganizationUser> confirmedOrganizationUsers, string defaultUserCollectionName)
|
||||
{
|
||||
var requiresDefaultCollections = await OrganizationRequiresDefaultCollectionAsync(organizationId, defaultUserCollectionName);
|
||||
if (!requiresDefaultCollections)
|
||||
if (!_featureService.IsEnabled(FeatureFlagKeys.CreateDefaultLocation))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var organizationUserIds = confirmedOrganizationUsers.Select(u => u.Id).ToList();
|
||||
await _collectionRepository.CreateDefaultCollectionsAsync(organizationId, organizationUserIds, defaultUserCollectionName);
|
||||
// Skip if no collection name provided (backwards compatibility)
|
||||
if (string.IsNullOrWhiteSpace(defaultUserCollectionName))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var policyEligibleOrganizationUserIds = await _policyRequirementQuery.GetManyByOrganizationIdAsync<OrganizationDataOwnershipPolicyRequirement>(organizationId);
|
||||
|
||||
var eligibleOrganizationUserIds = confirmedOrganizationUsers
|
||||
.Where(ou => policyEligibleOrganizationUserIds.Contains(ou.Id))
|
||||
.Select(ou => ou.Id)
|
||||
.ToList();
|
||||
|
||||
if (eligibleOrganizationUserIds.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await _collectionRepository.CreateDefaultCollectionsAsync(organizationId, eligibleOrganizationUserIds, defaultUserCollectionName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,12 +17,11 @@ public interface IPolicyRequirementQuery
|
||||
Task<T> GetAsync<T>(Guid userId) where T : IPolicyRequirement;
|
||||
|
||||
/// <summary>
|
||||
/// Get a policy requirement for a specific organization.
|
||||
/// This returns the policy requirement that represents the policy state for the entire organization.
|
||||
/// It will always return a value even if there are no policies that should be enforced.
|
||||
/// This should be used for organization-level policy checks.
|
||||
/// Get all organization user IDs within an organization that are affected by a given policy type.
|
||||
/// Respects role/status/provider exemptions via the policy factory's Enforce predicate.
|
||||
/// </summary>
|
||||
/// <param name="organizationId">The organization to check policies for.</param>
|
||||
/// <typeparam name="T">The IPolicyRequirement that corresponds to the policy you want to enforce.</typeparam>
|
||||
Task<T> GetByOrganizationAsync<T>(Guid organizationId) where T : IPolicyRequirement;
|
||||
/// <param name="organizationId">The organization to check.</param>
|
||||
/// <typeparam name="T">The IPolicyRequirement that corresponds to the policy type to evaluate.</typeparam>
|
||||
/// <returns>Organization user IDs for whom the policy applies within the organization.</returns>
|
||||
Task<IEnumerable<Guid>> GetManyByOrganizationIdAsync<T>(Guid organizationId) where T : IPolicyRequirement;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,8 @@ public class PolicyRequirementQuery(
|
||||
return requirement;
|
||||
}
|
||||
|
||||
public async Task<T> GetByOrganizationAsync<T>(Guid organizationId) where T : IPolicyRequirement
|
||||
public async Task<IEnumerable<Guid>> GetManyByOrganizationIdAsync<T>(Guid organizationId)
|
||||
where T : IPolicyRequirement
|
||||
{
|
||||
var factory = factories.OfType<IPolicyRequirementFactory<T>>().SingleOrDefault();
|
||||
if (factory is null)
|
||||
@@ -37,13 +38,14 @@ public class PolicyRequirementQuery(
|
||||
}
|
||||
|
||||
var organizationPolicyDetails = await GetOrganizationPolicyDetails(organizationId, factory.PolicyType);
|
||||
var filteredPolicies = organizationPolicyDetails
|
||||
.Cast<PolicyDetails>()
|
||||
.Where(policyDetails => policyDetails.PolicyType == factory.PolicyType)
|
||||
|
||||
var eligibleOrganizationUserIds = organizationPolicyDetails
|
||||
.Where(p => p.PolicyType == factory.PolicyType)
|
||||
.Where(factory.Enforce)
|
||||
.Select(p => p.OrganizationUserId)
|
||||
.ToList();
|
||||
var requirement = factory.Create(filteredPolicies);
|
||||
return requirement;
|
||||
|
||||
return eligibleOrganizationUserIds;
|
||||
}
|
||||
|
||||
private Task<IEnumerable<PolicyDetails>> GetPolicyDetails(Guid userId)
|
||||
|
||||
Reference in New Issue
Block a user