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

[SM-382] Service Account access policy checks (#2603)

The purpose of this PR is to add access policy checks to service account endpoints.
This commit is contained in:
Thomas Avery
2023-01-24 09:50:04 -06:00
committed by GitHub
parent bdea036c1f
commit aa9f859306
17 changed files with 691 additions and 101 deletions

View File

@ -1,4 +1,7 @@
using Bit.Core.Entities;
using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
using Bit.Core.SecretManagerFeatures.AccessTokens.Interfaces;
using Bit.Core.Utilities;
@ -7,16 +10,45 @@ namespace Bit.Commercial.Core.SecretManagerFeatures.AccessTokens;
public class CreateAccessTokenCommand : ICreateAccessTokenCommand
{
private readonly int _clientSecretMaxLength = 30;
private readonly IApiKeyRepository _apiKeyRepository;
private readonly int _clientSecretMaxLength = 30;
private readonly ICurrentContext _currentContext;
private readonly IServiceAccountRepository _serviceAccountRepository;
public CreateAccessTokenCommand(IApiKeyRepository apiKeyRepository)
public CreateAccessTokenCommand(
IApiKeyRepository apiKeyRepository,
ICurrentContext currentContext,
IServiceAccountRepository serviceAccountRepository)
{
_apiKeyRepository = apiKeyRepository;
_currentContext = currentContext;
_serviceAccountRepository = serviceAccountRepository;
}
public async Task<ApiKey> CreateAsync(ApiKey apiKey)
public async Task<ApiKey> CreateAsync(ApiKey apiKey, Guid userId)
{
if (apiKey.ServiceAccountId == null)
{
throw new BadRequestException();
}
var serviceAccount = await _serviceAccountRepository.GetByIdAsync(apiKey.ServiceAccountId.Value);
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 UnauthorizedAccessException();
}
apiKey.ClientSecret = CoreHelpers.SecureRandomString(_clientSecretMaxLength);
return await _apiKeyRepository.CreateAsync(apiKey);
}

View File

@ -1,4 +1,6 @@
using Bit.Core.Entities;
using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
using Bit.Core.Repositories;
using Bit.Core.SecretManagerFeatures.ServiceAccounts.Interfaces;
@ -8,22 +10,38 @@ namespace Bit.Commercial.Core.SecretManagerFeatures.ServiceAccounts;
public class UpdateServiceAccountCommand : IUpdateServiceAccountCommand
{
private readonly IServiceAccountRepository _serviceAccountRepository;
private readonly ICurrentContext _currentContext;
public UpdateServiceAccountCommand(IServiceAccountRepository serviceAccountRepository)
public UpdateServiceAccountCommand(IServiceAccountRepository serviceAccountRepository, ICurrentContext currentContext)
{
_serviceAccountRepository = serviceAccountRepository;
_currentContext = currentContext;
}
public async Task<ServiceAccount> UpdateAsync(ServiceAccount serviceAccount)
public async Task<ServiceAccount> UpdateAsync(ServiceAccount updatedServiceAccount, Guid userId)
{
var existingServiceAccount = await _serviceAccountRepository.GetByIdAsync(serviceAccount.Id);
if (existingServiceAccount == null)
var serviceAccount = await _serviceAccountRepository.GetByIdAsync(updatedServiceAccount.Id);
if (serviceAccount == null)
{
throw new NotFoundException();
}
serviceAccount.OrganizationId = existingServiceAccount.OrganizationId;
serviceAccount.CreationDate = existingServiceAccount.CreationDate;
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(updatedServiceAccount.Id, userId),
_ => false,
};
if (!hasAccess)
{
throw new UnauthorizedAccessException();
}
serviceAccount.Name = updatedServiceAccount.Name;
serviceAccount.RevisionDate = DateTime.UtcNow;
await _serviceAccountRepository.ReplaceAsync(serviceAccount);