mirror of
https://github.com/bitwarden/server
synced 2026-02-28 02:13:19 +00:00
PM-31847 Wire up UseMyItems organization ability (#7039)
Skip My Items creation if organization.UseMyItems is disabled
This commit is contained in:
@@ -101,6 +101,7 @@ public class AutomaticallyConfirmOrganizationUserCommand(IOrganizationUserReposi
|
||||
/// <returns>The result is a boolean value indicating whether a default collection should be created.</returns>
|
||||
private async Task<bool> ShouldCreateDefaultCollectionAsync(AutomaticallyConfirmOrganizationUserValidationRequest request) =>
|
||||
!string.IsNullOrWhiteSpace(request.DefaultUserCollectionName)
|
||||
&& request.Organization!.UseMyItems
|
||||
&& (await policyRequirementQuery.GetAsync<OrganizationDataOwnershipPolicyRequirement>(request.OrganizationUser!.UserId!.Value))
|
||||
.RequiresDefaultCollectionOnConfirm(request.Organization!.Id);
|
||||
|
||||
|
||||
@@ -72,10 +72,13 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
|
||||
public async Task<OrganizationUser> ConfirmUserAsync(Guid organizationId, Guid organizationUserId, string key,
|
||||
Guid confirmingUserId, string defaultUserCollectionName = null)
|
||||
{
|
||||
var organization = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
|
||||
var result = await SaveChangesToDatabaseAsync(
|
||||
organizationId,
|
||||
new Dictionary<Guid, string>() { { organizationUserId, key } },
|
||||
confirmingUserId);
|
||||
confirmingUserId,
|
||||
organization);
|
||||
|
||||
if (!result.Any())
|
||||
{
|
||||
@@ -88,7 +91,7 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
|
||||
throw new BadRequestException(error);
|
||||
}
|
||||
|
||||
await CreateDefaultCollectionAsync(orgUser, defaultUserCollectionName);
|
||||
await CreateDefaultCollectionAsync(orgUser, organization, defaultUserCollectionName);
|
||||
|
||||
return orgUser;
|
||||
}
|
||||
@@ -96,7 +99,9 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
|
||||
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 organization = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
|
||||
var result = await SaveChangesToDatabaseAsync(organizationId, keys, confirmingUserId, organization);
|
||||
|
||||
var confirmedOrganizationUsers = result
|
||||
.Where(r => string.IsNullOrEmpty(r.Item2))
|
||||
@@ -105,18 +110,18 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
|
||||
|
||||
if (confirmedOrganizationUsers.Count == 1)
|
||||
{
|
||||
await CreateDefaultCollectionAsync(confirmedOrganizationUsers.Single(), defaultUserCollectionName);
|
||||
await CreateDefaultCollectionAsync(confirmedOrganizationUsers.Single(), organization, defaultUserCollectionName);
|
||||
}
|
||||
else if (confirmedOrganizationUsers.Count > 1)
|
||||
{
|
||||
await CreateManyDefaultCollectionsAsync(organizationId, confirmedOrganizationUsers, defaultUserCollectionName);
|
||||
await CreateManyDefaultCollectionsAsync(organization, confirmedOrganizationUsers, defaultUserCollectionName);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task<List<Tuple<OrganizationUser, string>>> SaveChangesToDatabaseAsync(Guid organizationId, Dictionary<Guid, string> keys,
|
||||
Guid confirmingUserId)
|
||||
Guid confirmingUserId, Organization organization)
|
||||
{
|
||||
var selectedOrganizationUsers = await _organizationUserRepository.GetManyAsync(keys.Keys);
|
||||
var validSelectedOrganizationUsers = selectedOrganizationUsers
|
||||
@@ -129,8 +134,6 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
|
||||
}
|
||||
|
||||
var validSelectedUserIds = validSelectedOrganizationUsers.Select(u => u.UserId.Value).ToList();
|
||||
|
||||
var organization = await _organizationRepository.GetByIdAsync(organizationId);
|
||||
var allUsersOrgs = await _organizationUserRepository.GetManyByManyUsersAsync(validSelectedUserIds);
|
||||
|
||||
var users = await _userRepository.GetManyAsync(validSelectedUserIds);
|
||||
@@ -278,8 +281,9 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
|
||||
/// Creates a default collection for a single user if required by the Organization Data Ownership policy.
|
||||
/// </summary>
|
||||
/// <param name="organizationUser">The organization user who has just been confirmed.</param>
|
||||
/// <param name="organization">The organization.</param>
|
||||
/// <param name="defaultUserCollectionName">The encrypted default user collection name.</param>
|
||||
private async Task CreateDefaultCollectionAsync(OrganizationUser organizationUser, string defaultUserCollectionName)
|
||||
private async Task CreateDefaultCollectionAsync(OrganizationUser organizationUser, Organization organization, string defaultUserCollectionName)
|
||||
{
|
||||
// Skip if no collection name provided (backwards compatibility)
|
||||
if (string.IsNullOrWhiteSpace(defaultUserCollectionName))
|
||||
@@ -287,6 +291,12 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip if organization has disabled My Items
|
||||
if (!organization.UseMyItems)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var organizationDataOwnershipPolicy = await _policyRequirementQuery.GetAsync<OrganizationDataOwnershipPolicyRequirement>(organizationUser.UserId!.Value);
|
||||
if (!organizationDataOwnershipPolicy.RequiresDefaultCollectionOnConfirm(organizationUser.OrganizationId))
|
||||
{
|
||||
@@ -302,10 +312,10 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
|
||||
/// <summary>
|
||||
/// Creates default collections for multiple users if required by the Organization Data Ownership policy.
|
||||
/// </summary>
|
||||
/// <param name="organizationId">The organization ID.</param>
|
||||
/// <param name="organization">The organization.</param>
|
||||
/// <param name="confirmedOrganizationUsers">The confirmed organization users.</param>
|
||||
/// <param name="defaultUserCollectionName">The encrypted default user collection name.</param>
|
||||
private async Task CreateManyDefaultCollectionsAsync(Guid organizationId,
|
||||
private async Task CreateManyDefaultCollectionsAsync(Organization organization,
|
||||
IEnumerable<OrganizationUser> confirmedOrganizationUsers, string defaultUserCollectionName)
|
||||
{
|
||||
// Skip if no collection name provided (backwards compatibility)
|
||||
@@ -314,8 +324,14 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip if organization has disabled My Items
|
||||
if (!organization.UseMyItems)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var policyEligibleOrganizationUserIds = await _policyRequirementQuery
|
||||
.GetManyByOrganizationIdAsync<OrganizationDataOwnershipPolicyRequirement>(organizationId);
|
||||
.GetManyByOrganizationIdAsync<OrganizationDataOwnershipPolicyRequirement>(organization.Id);
|
||||
|
||||
var eligibleOrganizationUserIds = confirmedOrganizationUsers
|
||||
.Where(ou => policyEligibleOrganizationUserIds.Contains(ou.Id))
|
||||
@@ -327,7 +343,7 @@ public class ConfirmOrganizationUserCommand : IConfirmOrganizationUserCommand
|
||||
return;
|
||||
}
|
||||
|
||||
await _collectionRepository.CreateDefaultCollectionsAsync(organizationId, eligibleOrganizationUserIds, defaultUserCollectionName);
|
||||
await _collectionRepository.CreateDefaultCollectionsAsync(organization.Id, eligibleOrganizationUserIds, defaultUserCollectionName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -106,6 +106,7 @@ public class RestoreOrganizationUserCommand(
|
||||
await organizationUserRepository.RestoreAsync(organizationUser.Id, status);
|
||||
|
||||
if (organizationUser.UserId.HasValue
|
||||
&& organization.UseMyItems
|
||||
&& (await policyRequirementQuery.GetAsync<OrganizationDataOwnershipPolicyRequirement>(organizationUser.UserId.Value)).State == OrganizationDataOwnershipState.Enabled
|
||||
&& status == OrganizationUserStatusType.Confirmed
|
||||
&& featureService.IsEnabled(FeatureFlagKeys.DefaultUserCollectionRestore)
|
||||
@@ -253,20 +254,25 @@ public class RestoreOrganizationUserCommand(
|
||||
|
||||
if (featureService.IsEnabled(FeatureFlagKeys.DefaultUserCollectionRestore))
|
||||
{
|
||||
await CreateDefaultCollectionsForConfirmedUsersAsync(organizationId, defaultCollectionName,
|
||||
await CreateDefaultCollectionsForConfirmedUsersAsync(organization, defaultCollectionName,
|
||||
result.Where(r => r.Item2 == "").Select(x => x.Item1).ToList());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private async Task CreateDefaultCollectionsForConfirmedUsersAsync(Guid organizationId, string defaultCollectionName,
|
||||
private async Task CreateDefaultCollectionsForConfirmedUsersAsync(Organization organization, string defaultCollectionName,
|
||||
ICollection<OrganizationUser> restoredUsers)
|
||||
{
|
||||
if (!organization.UseMyItems)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(defaultCollectionName))
|
||||
{
|
||||
var organizationUsersDataOwnershipEnabled = (await policyRequirementQuery
|
||||
.GetManyByOrganizationIdAsync<OrganizationDataOwnershipPolicyRequirement>(organizationId))
|
||||
.GetManyByOrganizationIdAsync<OrganizationDataOwnershipPolicyRequirement>(organization.Id))
|
||||
.ToList();
|
||||
|
||||
var usersToCreateDefaultCollectionsFor = restoredUsers.Where(x =>
|
||||
@@ -275,7 +281,7 @@ public class RestoreOrganizationUserCommand(
|
||||
|
||||
if (usersToCreateDefaultCollectionsFor.Count != 0)
|
||||
{
|
||||
await collectionRepository.CreateDefaultCollectionsAsync(organizationId,
|
||||
await collectionRepository.CreateDefaultCollectionsAsync(organization.Id,
|
||||
usersToCreateDefaultCollectionsFor.Select(x => x.Id),
|
||||
defaultCollectionName);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ namespace Bit.Core.AdminConsole.OrganizationFeatures.Policies.PolicyValidators;
|
||||
public class OrganizationDataOwnershipPolicyValidator(
|
||||
IPolicyRepository policyRepository,
|
||||
ICollectionRepository collectionRepository,
|
||||
IOrganizationRepository organizationRepository,
|
||||
IEnumerable<IPolicyRequirementFactory<IPolicyRequirement>> factories)
|
||||
: OrganizationPolicyValidator(policyRepository, factories), IPostSavePolicySideEffect, IOnPolicyPostUpdateEvent
|
||||
{
|
||||
@@ -52,6 +53,20 @@ public class OrganizationDataOwnershipPolicyValidator(
|
||||
|
||||
private async Task UpsertDefaultCollectionsForUsersAsync(PolicyUpdate policyUpdate, string defaultCollectionName)
|
||||
{
|
||||
// FIXME: we should use the organizationAbility cache here, but it is currently flaky
|
||||
// and it's not obvious how to handle a cache failure.
|
||||
// https://bitwarden.atlassian.net/browse/PM-32699
|
||||
var organization = await organizationRepository.GetByIdAsync(policyUpdate.OrganizationId);
|
||||
if (organization == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Organization with ID {policyUpdate.OrganizationId} not found.");
|
||||
}
|
||||
|
||||
if (!organization.UseMyItems)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var requirements = await GetUserPolicyRequirementsByOrganizationIdAsync<OrganizationDataOwnershipPolicyRequirement>(policyUpdate.OrganizationId, policyUpdate.Type);
|
||||
|
||||
var userOrgIds = requirements
|
||||
|
||||
Reference in New Issue
Block a user