1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-04 01:22:50 -05:00

[SM-789] Extract authorization from service account delete command (#2999)

* Extract authorization from SA delete command

* swap to IEnumerable

---------

Co-authored-by: Matt Bishop <mbishop@bitwarden.com>
This commit is contained in:
Thomas Avery
2023-07-12 15:32:40 -05:00
committed by GitHub
parent b629c31de9
commit d6a45d4802
8 changed files with 246 additions and 70 deletions

View File

@ -44,6 +44,9 @@ public class
case not null when requirement == ServiceAccountOperations.Update:
await CanUpdateServiceAccountAsync(context, requirement, resource);
break;
case not null when requirement == ServiceAccountOperations.Delete:
await CanDeleteServiceAccountAsync(context, requirement, resource);
break;
case not null when requirement == ServiceAccountOperations.CreateAccessToken:
await CanCreateAccessTokenAsync(context, requirement, resource);
break;
@ -107,6 +110,21 @@ public class
}
}
private async Task CanDeleteServiceAccountAsync(AuthorizationHandlerContext context,
ServiceAccountOperationRequirement requirement, ServiceAccount resource)
{
var (accessClient, userId) =
await _accessClientQuery.GetAccessClientAsync(context.User, resource.OrganizationId);
var access =
await _serviceAccountRepository.AccessToServiceAccountAsync(resource.Id, userId,
accessClient);
if (access.Write)
{
context.Succeed(requirement);
}
}
private async Task CanCreateAccessTokenAsync(AuthorizationHandlerContext context,
ServiceAccountOperationRequirement requirement, ServiceAccount resource)
{

View File

@ -1,7 +1,4 @@
using Bit.Core.Context;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.SecretsManager.Commands.ServiceAccounts.Interfaces;
using Bit.Core.SecretsManager.Commands.ServiceAccounts.Interfaces;
using Bit.Core.SecretsManager.Entities;
using Bit.Core.SecretsManager.Repositories;
@ -10,74 +7,15 @@ namespace Bit.Commercial.Core.SecretsManager.Commands.ServiceAccounts;
public class DeleteServiceAccountsCommand : IDeleteServiceAccountsCommand
{
private readonly IServiceAccountRepository _serviceAccountRepository;
private readonly ICurrentContext _currentContext;
public DeleteServiceAccountsCommand(
IServiceAccountRepository serviceAccountRepository,
ICurrentContext currentContext)
IServiceAccountRepository serviceAccountRepository)
{
_serviceAccountRepository = serviceAccountRepository;
_currentContext = currentContext;
}
public async Task<List<Tuple<ServiceAccount, string>>> DeleteServiceAccounts(List<Guid> ids, Guid userId)
public async Task DeleteServiceAccounts(IEnumerable<ServiceAccount> serviceAccounts)
{
if (ids.Any() != true || userId == new Guid())
{
throw new ArgumentNullException();
}
var serviceAccounts = (await _serviceAccountRepository.GetManyByIds(ids))?.ToList();
if (serviceAccounts?.Any() != true || serviceAccounts.Count != ids.Count)
{
throw new NotFoundException();
}
// Ensure all service accounts belongs to the same organization
var organizationId = serviceAccounts.First().OrganizationId;
if (serviceAccounts.Any(p => p.OrganizationId != organizationId))
{
throw new BadRequestException();
}
if (!_currentContext.AccessSecretsManager(organizationId))
{
throw new NotFoundException();
}
var orgAdmin = await _currentContext.OrganizationAdmin(organizationId);
var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin);
var results = new List<Tuple<ServiceAccount, String>>(serviceAccounts.Count);
var deleteIds = new List<Guid>();
foreach (var sa in serviceAccounts)
{
var hasAccess = accessClient switch
{
AccessClientType.NoAccessCheck => true,
AccessClientType.User => await _serviceAccountRepository.UserHasWriteAccessToServiceAccount(sa.Id, userId),
_ => false,
};
if (!hasAccess)
{
results.Add(new Tuple<ServiceAccount, string>(sa, "access denied"));
}
else
{
results.Add(new Tuple<ServiceAccount, string>(sa, ""));
deleteIds.Add(sa.Id);
}
}
if (deleteIds.Count > 0)
{
await _serviceAccountRepository.DeleteManyByIdAsync(deleteIds);
}
return results;
await _serviceAccountRepository.DeleteManyByIdAsync(serviceAccounts.Select(sa => sa.Id));
}
}