1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-02 16:42:50 -05:00

[SM-788] Extract authorization from secret delete command (#3003)

* Extract authorization from secret delete command
This commit is contained in:
Thomas Avery
2023-06-27 13:12:34 -05:00
committed by GitHub
parent c1723d9e90
commit d020c49c0e
9 changed files with 287 additions and 196 deletions

View File

@ -41,6 +41,9 @@ public class SecretAuthorizationHandler : AuthorizationHandler<SecretOperationRe
case not null when requirement == SecretOperations.Update:
await CanUpdateSecretAsync(context, requirement, resource);
break;
case not null when requirement == SecretOperations.Delete:
await CanDeleteSecretAsync(context, requirement, resource);
break;
default:
throw new ArgumentException("Unsupported operation requirement type provided.", nameof(requirement));
}
@ -120,4 +123,22 @@ public class SecretAuthorizationHandler : AuthorizationHandler<SecretOperationRe
context.Succeed(requirement);
}
}
private async Task CanDeleteSecretAsync(AuthorizationHandlerContext context,
SecretOperationRequirement requirement, Secret resource)
{
var (accessClient, userId) = await _accessClientQuery.GetAccessClientAsync(context.User, resource.OrganizationId);
if (accessClient == AccessClientType.ServiceAccount)
{
return;
}
var access = await _secretRepository.AccessToSecretAsync(resource.Id, userId, accessClient);
if (access.Write)
{
context.Succeed(requirement);
}
}
}

View File

@ -1,7 +1,4 @@
using Bit.Core.Context;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.SecretsManager.Commands.Secrets.Interfaces;
using Bit.Core.SecretsManager.Commands.Secrets.Interfaces;
using Bit.Core.SecretsManager.Entities;
using Bit.Core.SecretsManager.Repositories;
@ -9,73 +6,16 @@ namespace Bit.Commercial.Core.SecretsManager.Commands.Secrets;
public class DeleteSecretCommand : IDeleteSecretCommand
{
private readonly ICurrentContext _currentContext;
private readonly ISecretRepository _secretRepository;
private readonly IProjectRepository _projectRepository;
public DeleteSecretCommand(ISecretRepository secretRepository, IProjectRepository projectRepository, ICurrentContext currentContext)
public DeleteSecretCommand(ISecretRepository secretRepository)
{
_currentContext = currentContext;
_secretRepository = secretRepository;
_projectRepository = projectRepository;
}
public async Task<List<Tuple<Secret, string>>> DeleteSecrets(List<Guid> ids, Guid userId)
public async Task DeleteSecrets(IEnumerable<Secret> secrets)
{
var secrets = (await _secretRepository.GetManyByIds(ids)).ToList();
if (secrets.Any() != true)
{
throw new NotFoundException();
}
// Ensure all secrets belongs to the same organization
var organizationId = secrets.First().OrganizationId;
if (secrets.Any(secret => secret.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<Secret, string>>();
var deleteIds = new List<Guid>();
foreach (var secret in secrets)
{
var hasAccess = orgAdmin;
if (secret.Projects != null && secret.Projects?.Count > 0)
{
var projectId = secret.Projects.First().Id;
hasAccess = (await _projectRepository.AccessToProjectAsync(projectId, userId, accessClient)).Write;
}
if (!hasAccess || accessClient == AccessClientType.ServiceAccount)
{
results.Add(new Tuple<Secret, string>(secret, "access denied"));
}
else
{
deleteIds.Add(secret.Id);
results.Add(new Tuple<Secret, string>(secret, ""));
}
}
if (deleteIds.Count > 0)
{
await _secretRepository.SoftDeleteManyByIdAsync(deleteIds);
}
return results;
await _secretRepository.SoftDeleteManyByIdAsync(secrets.Select(s => s.Id));
}
}