mirror of
https://github.com/bitwarden/server.git
synced 2025-06-30 15:42:48 -05:00
[PM-1879] Allow custom users to grant the same custom permissions that they have (#2897)
* [PM-1879] Replaced JsonSerializer.Serialize with CoreHelpers.ClassToJsonData * [PM-1879] Changed OrganizationService.SaveUserAsync to check Custom permissions * [PM-1879] Added unit tests for saving Custom permissions using a Custom user * [PM-1879] Added method OrganizationUser.GetPermissions to deserialize the Permissions property * [PM-1879] Refactored ValidateCustomPermissionsGrant to return bool * [PM-1879] Added unit test SaveUser_WithCustomPermission_WhenUpgradingToAdmin_Throws
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Models;
|
||||
using Bit.Core.Models.Data;
|
||||
using Bit.Core.Utilities;
|
||||
|
||||
namespace Bit.Core.Entities;
|
||||
@ -28,4 +29,10 @@ public class OrganizationUser : ITableObject<Guid>, IExternal
|
||||
{
|
||||
Id = CoreHelpers.GenerateComb();
|
||||
}
|
||||
|
||||
public Permissions GetPermissions()
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(Permissions) ? null
|
||||
: CoreHelpers.LoadClassFromJsonData<Permissions>(Permissions);
|
||||
}
|
||||
}
|
||||
|
@ -986,10 +986,10 @@ public class OrganizationService : IOrganizationService
|
||||
.Select(i => i.invite.Type.Value));
|
||||
if (invitingUserId.HasValue && inviteTypes.Count > 0)
|
||||
{
|
||||
foreach (var type in inviteTypes)
|
||||
foreach (var (invite, _) in invites)
|
||||
{
|
||||
await ValidateOrganizationUserUpdatePermissions(organizationId, type, null);
|
||||
await ValidateOrganizationCustomPermissionsEnabledAsync(organizationId, type);
|
||||
await ValidateOrganizationUserUpdatePermissions(organizationId, invite.Type.Value, null, invite.Permissions);
|
||||
await ValidateOrganizationCustomPermissionsEnabledAsync(organizationId, invite.Type.Value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1536,7 +1536,7 @@ public class OrganizationService : IOrganizationService
|
||||
|
||||
if (savingUserId.HasValue)
|
||||
{
|
||||
await ValidateOrganizationUserUpdatePermissions(user.OrganizationId, user.Type, originalUser.Type);
|
||||
await ValidateOrganizationUserUpdatePermissions(user.OrganizationId, user.Type, originalUser.Type, user.GetPermissions());
|
||||
}
|
||||
|
||||
await ValidateOrganizationCustomPermissionsEnabledAsync(user.OrganizationId, user.Type);
|
||||
@ -1709,7 +1709,7 @@ public class OrganizationService : IOrganizationService
|
||||
{
|
||||
if (loggedInUserId.HasValue)
|
||||
{
|
||||
await ValidateOrganizationUserUpdatePermissions(organizationUser.OrganizationId, organizationUser.Type, null);
|
||||
await ValidateOrganizationUserUpdatePermissions(organizationUser.OrganizationId, organizationUser.Type, null, organizationUser.GetPermissions());
|
||||
}
|
||||
await _organizationUserRepository.UpdateGroupsAsync(organizationUser.Id, groupIds);
|
||||
await _eventService.LogOrganizationUserEventAsync(organizationUser,
|
||||
@ -2100,8 +2100,7 @@ public class OrganizationService : IOrganizationService
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ValidateOrganizationUserUpdatePermissions(Guid organizationId, OrganizationUserType newType,
|
||||
OrganizationUserType? oldType)
|
||||
private async Task ValidateOrganizationUserUpdatePermissions(Guid organizationId, OrganizationUserType newType, OrganizationUserType? oldType, Permissions permissions)
|
||||
{
|
||||
if (await _currentContext.OrganizationOwner(organizationId))
|
||||
{
|
||||
@ -2118,11 +2117,6 @@ public class OrganizationService : IOrganizationService
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldType == OrganizationUserType.Custom || newType == OrganizationUserType.Custom)
|
||||
{
|
||||
throw new BadRequestException("Only Owners and Admins can configure Custom accounts.");
|
||||
}
|
||||
|
||||
if (!await _currentContext.ManageUsers(organizationId))
|
||||
{
|
||||
throw new BadRequestException("Your account does not have permission to manage users.");
|
||||
@ -2132,6 +2126,11 @@ public class OrganizationService : IOrganizationService
|
||||
{
|
||||
throw new BadRequestException("Custom users can not manage Admins or Owners.");
|
||||
}
|
||||
|
||||
if (newType == OrganizationUserType.Custom && !await ValidateCustomPermissionsGrant(organizationId, permissions))
|
||||
{
|
||||
throw new BadRequestException("Custom users can only grant the same custom permissions that they have.");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ValidateOrganizationCustomPermissionsEnabledAsync(Guid organizationId, OrganizationUserType newType)
|
||||
@ -2153,6 +2152,86 @@ public class OrganizationService : IOrganizationService
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> ValidateCustomPermissionsGrant(Guid organizationId, Permissions permissions)
|
||||
{
|
||||
if (permissions == null || await _currentContext.OrganizationOwner(organizationId) || await _currentContext.OrganizationAdmin(organizationId))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (permissions.ManageUsers && !await _currentContext.ManageUsers(organizationId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (permissions.AccessReports && !await _currentContext.AccessReports(organizationId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (permissions.ManageGroups && !await _currentContext.ManageGroups(organizationId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (permissions.ManagePolicies && !await _currentContext.ManagePolicies(organizationId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (permissions.ManageScim && !await _currentContext.ManageScim(organizationId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (permissions.ManageSso && !await _currentContext.ManageSso(organizationId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (permissions.AccessEventLogs && !await _currentContext.AccessEventLogs(organizationId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (permissions.AccessImportExport && !await _currentContext.AccessImportExport(organizationId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (permissions.CreateNewCollections && !await _currentContext.CreateNewCollections(organizationId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (permissions.DeleteAnyCollection && !await _currentContext.DeleteAnyCollection(organizationId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (permissions.DeleteAssignedCollections && !await _currentContext.DeleteAssignedCollections(organizationId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (permissions.EditAnyCollection && !await _currentContext.EditAnyCollection(organizationId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (permissions.EditAssignedCollections && !await _currentContext.EditAssignedCollections(organizationId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (permissions.ManageResetPassword && !await _currentContext.ManageResetPassword(organizationId))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private async Task ValidateDeleteOrganizationAsync(Organization organization)
|
||||
{
|
||||
var ssoConfig = await _ssoConfigRepository.GetByOrganizationIdAsync(organization.Id);
|
||||
|
Reference in New Issue
Block a user