mirror of
https://github.com/bitwarden/server.git
synced 2025-07-18 16:11:28 -05:00
[PM-19703] Fix admin count logic to exclude current organization (#5918)
This commit is contained in:
@ -1,11 +1,12 @@
|
||||
#nullable enable
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models.Data;
|
||||
|
||||
namespace Bit.Core.AdminConsole.OrganizationFeatures.OrganizationUsers.Interfaces;
|
||||
|
||||
public interface IUpdateOrganizationUserCommand
|
||||
{
|
||||
Task UpdateUserAsync(OrganizationUser organizationUser, Guid? savingUserId,
|
||||
Task UpdateUserAsync(OrganizationUser organizationUser, OrganizationUserType existingUserType, Guid? savingUserId,
|
||||
List<CollectionAccessSelection>? collectionAccess, IEnumerable<Guid>? groupAccess);
|
||||
}
|
||||
|
@ -55,11 +55,13 @@ public class UpdateOrganizationUserCommand : IUpdateOrganizationUserCommand
|
||||
/// Update an organization user.
|
||||
/// </summary>
|
||||
/// <param name="organizationUser">The modified organization user to save.</param>
|
||||
/// <param name="existingUserType">The current type (member role) of the user.</param>
|
||||
/// <param name="savingUserId">The userId of the currently logged in user who is making the change.</param>
|
||||
/// <param name="collectionAccess">The user's updated collection access. If set to null, this removes all collection access.</param>
|
||||
/// <param name="groupAccess">The user's updated group access. If set to null, groups are not updated.</param>
|
||||
/// <exception cref="BadRequestException"></exception>
|
||||
public async Task UpdateUserAsync(OrganizationUser organizationUser, Guid? savingUserId,
|
||||
public async Task UpdateUserAsync(OrganizationUser organizationUser, OrganizationUserType existingUserType,
|
||||
Guid? savingUserId,
|
||||
List<CollectionAccessSelection>? collectionAccess, IEnumerable<Guid>? groupAccess)
|
||||
{
|
||||
// Avoid multiple enumeration
|
||||
@ -83,15 +85,7 @@ public class UpdateOrganizationUserCommand : IUpdateOrganizationUserCommand
|
||||
throw new NotFoundException();
|
||||
}
|
||||
|
||||
if (organizationUser.UserId.HasValue && organization.PlanType == PlanType.Free && organizationUser.Type is OrganizationUserType.Admin or OrganizationUserType.Owner)
|
||||
{
|
||||
// Since free organizations only supports a few users there is not much point in avoiding N+1 queries for this.
|
||||
var adminCount = await _organizationUserRepository.GetCountByFreeOrganizationAdminUserAsync(organizationUser.UserId.Value);
|
||||
if (adminCount > 0)
|
||||
{
|
||||
throw new BadRequestException("User can only be an admin of one free organization.");
|
||||
}
|
||||
}
|
||||
await EnsureUserCannotBeAdminOrOwnerForMultipleFreeOrganizationAsync(organizationUser, existingUserType, organization);
|
||||
|
||||
if (collectionAccessList.Count != 0)
|
||||
{
|
||||
@ -151,6 +145,40 @@ public class UpdateOrganizationUserCommand : IUpdateOrganizationUserCommand
|
||||
await _eventService.LogOrganizationUserEventAsync(organizationUser, EventType.OrganizationUser_Updated);
|
||||
}
|
||||
|
||||
private async Task EnsureUserCannotBeAdminOrOwnerForMultipleFreeOrganizationAsync(OrganizationUser updatedOrgUser, OrganizationUserType existingUserType, Entities.Organization organization)
|
||||
{
|
||||
|
||||
if (organization.PlanType != PlanType.Free)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!updatedOrgUser.UserId.HasValue)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (updatedOrgUser.Type is not (OrganizationUserType.Admin or OrganizationUserType.Owner))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Since free organizations only supports a few users there is not much point in avoiding N+1 queries for this.
|
||||
var adminCount = await _organizationUserRepository.GetCountByFreeOrganizationAdminUserAsync(updatedOrgUser.UserId!.Value);
|
||||
|
||||
var isCurrentAdminOrOwner = existingUserType is OrganizationUserType.Admin or OrganizationUserType.Owner;
|
||||
|
||||
if (isCurrentAdminOrOwner && adminCount <= 1)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isCurrentAdminOrOwner && adminCount == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
throw new BadRequestException("User can only be an admin of one free organization.");
|
||||
}
|
||||
|
||||
private async Task ValidateCollectionAccessAsync(OrganizationUser originalUser,
|
||||
ICollection<CollectionAccessSelection> collectionAccess)
|
||||
{
|
||||
|
Reference in New Issue
Block a user