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:
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user