1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-16 23:27:30 -05:00

[SM-705] Extract Authorization from Access Token Commands (#2928)

* refactor authorization for access token commands

* Unit tests for authorization handler
This commit is contained in:
Thomas Avery
2023-06-13 15:30:44 -05:00
committed by GitHub
parent b7a40406af
commit 3449d28c83
8 changed files with 389 additions and 243 deletions

View File

@ -44,6 +44,15 @@ public class
case not null when requirement == ServiceAccountOperations.Update:
await CanUpdateServiceAccountAsync(context, requirement, resource);
break;
case not null when requirement == ServiceAccountOperations.CreateAccessToken:
await CanCreateAccessTokenAsync(context, requirement, resource);
break;
case not null when requirement == ServiceAccountOperations.ReadAccessTokens:
await CanReadAccessTokensAsync(context, requirement, resource);
break;
case not null when requirement == ServiceAccountOperations.RevokeAccessTokens:
await CanRevokeAccessTokensAsync(context, requirement, resource);
break;
default:
throw new ArgumentException("Unsupported operation requirement type provided.",
nameof(requirement));
@ -97,4 +106,49 @@ public class
context.Succeed(requirement);
}
}
private async Task CanCreateAccessTokenAsync(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 CanReadAccessTokensAsync(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.Read)
{
context.Succeed(requirement);
}
}
private async Task CanRevokeAccessTokensAsync(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);
}
}
}

View File

@ -1,6 +1,4 @@
using Bit.Core.Context;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Exceptions;
using Bit.Core.SecretsManager.Commands.AccessTokens.Interfaces;
using Bit.Core.SecretsManager.Entities;
using Bit.Core.SecretsManager.Repositories;
@ -10,51 +8,21 @@ namespace Bit.Commercial.Core.SecretsManager.Commands.AccessTokens;
public class CreateAccessTokenCommand : ICreateAccessTokenCommand
{
private const int _clientSecretMaxLength = 30;
private readonly IApiKeyRepository _apiKeyRepository;
private readonly int _clientSecretMaxLength = 30;
private readonly ICurrentContext _currentContext;
private readonly IServiceAccountRepository _serviceAccountRepository;
public CreateAccessTokenCommand(
IApiKeyRepository apiKeyRepository,
ICurrentContext currentContext,
IServiceAccountRepository serviceAccountRepository)
public CreateAccessTokenCommand(IApiKeyRepository apiKeyRepository)
{
_apiKeyRepository = apiKeyRepository;
_currentContext = currentContext;
_serviceAccountRepository = serviceAccountRepository;
}
public async Task<ApiKey> CreateAsync(ApiKey apiKey, Guid userId)
public async Task<ApiKey> CreateAsync(ApiKey apiKey)
{
if (apiKey.ServiceAccountId == null)
{
throw new BadRequestException();
}
var serviceAccount = await _serviceAccountRepository.GetByIdAsync(apiKey.ServiceAccountId.Value);
if (!_currentContext.AccessSecretsManager(serviceAccount.OrganizationId))
{
throw new NotFoundException();
}
var orgAdmin = await _currentContext.OrganizationAdmin(serviceAccount.OrganizationId);
var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin);
var hasAccess = accessClient switch
{
AccessClientType.NoAccessCheck => true,
AccessClientType.User => await _serviceAccountRepository.UserHasWriteAccessToServiceAccount(
apiKey.ServiceAccountId.Value, userId),
_ => false,
};
if (!hasAccess)
{
throw new NotFoundException();
}
apiKey.ClientSecret = CoreHelpers.SecureRandomString(_clientSecretMaxLength);
return await _apiKeyRepository.CreateAsync(apiKey);
}