mirror of
https://github.com/bitwarden/server.git
synced 2024-11-25 12:45:18 +01:00
[SM-722] Add optional access to secrets for service account lists (#3074)
* Add access to secret count to service account list * dotnet format * refactor into query * Remove duplicate * Add new method to noop
This commit is contained in:
parent
d94a54516e
commit
73c6421bd3
@ -0,0 +1,36 @@
|
|||||||
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.SecretsManager.Models.Data;
|
||||||
|
using Bit.Core.SecretsManager.Queries.ServiceAccounts.Interfaces;
|
||||||
|
using Bit.Core.SecretsManager.Repositories;
|
||||||
|
|
||||||
|
namespace Bit.Commercial.Core.SecretsManager.Queries.ServiceAccounts;
|
||||||
|
|
||||||
|
public class ServiceAccountSecretsDetailsQuery : IServiceAccountSecretsDetailsQuery
|
||||||
|
{
|
||||||
|
private readonly IServiceAccountRepository _serviceAccountRepository;
|
||||||
|
|
||||||
|
public ServiceAccountSecretsDetailsQuery(IServiceAccountRepository serviceAccountRepository)
|
||||||
|
{
|
||||||
|
_serviceAccountRepository = serviceAccountRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<ServiceAccountSecretsDetails>> GetManyByOrganizationIdAsync(
|
||||||
|
Guid organizationId, Guid userId, AccessClientType accessClient, bool includeAccessToSecrets)
|
||||||
|
{
|
||||||
|
if (includeAccessToSecrets)
|
||||||
|
{
|
||||||
|
return await _serviceAccountRepository.GetManyByOrganizationIdWithSecretsDetailsAsync(organizationId,
|
||||||
|
userId,
|
||||||
|
accessClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
var serviceAccounts =
|
||||||
|
await _serviceAccountRepository.GetManyByOrganizationIdAsync(organizationId, userId, accessClient);
|
||||||
|
|
||||||
|
return serviceAccounts.Select(sa => new ServiceAccountSecretsDetails
|
||||||
|
{
|
||||||
|
ServiceAccount = sa,
|
||||||
|
AccessToSecrets = 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ using Bit.Commercial.Core.SecretsManager.Commands.Secrets;
|
|||||||
using Bit.Commercial.Core.SecretsManager.Commands.ServiceAccounts;
|
using Bit.Commercial.Core.SecretsManager.Commands.ServiceAccounts;
|
||||||
using Bit.Commercial.Core.SecretsManager.Commands.Trash;
|
using Bit.Commercial.Core.SecretsManager.Commands.Trash;
|
||||||
using Bit.Commercial.Core.SecretsManager.Queries;
|
using Bit.Commercial.Core.SecretsManager.Queries;
|
||||||
|
using Bit.Commercial.Core.SecretsManager.Queries.ServiceAccounts;
|
||||||
using Bit.Core.SecretsManager.Commands.AccessPolicies.Interfaces;
|
using Bit.Core.SecretsManager.Commands.AccessPolicies.Interfaces;
|
||||||
using Bit.Core.SecretsManager.Commands.AccessTokens.Interfaces;
|
using Bit.Core.SecretsManager.Commands.AccessTokens.Interfaces;
|
||||||
using Bit.Core.SecretsManager.Commands.Porting.Interfaces;
|
using Bit.Core.SecretsManager.Commands.Porting.Interfaces;
|
||||||
@ -18,6 +19,7 @@ using Bit.Core.SecretsManager.Commands.Secrets.Interfaces;
|
|||||||
using Bit.Core.SecretsManager.Commands.ServiceAccounts.Interfaces;
|
using Bit.Core.SecretsManager.Commands.ServiceAccounts.Interfaces;
|
||||||
using Bit.Core.SecretsManager.Commands.Trash.Interfaces;
|
using Bit.Core.SecretsManager.Commands.Trash.Interfaces;
|
||||||
using Bit.Core.SecretsManager.Queries.Interfaces;
|
using Bit.Core.SecretsManager.Queries.Interfaces;
|
||||||
|
using Bit.Core.SecretsManager.Queries.ServiceAccounts.Interfaces;
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
@ -32,6 +34,7 @@ public static class SecretsManagerCollectionExtensions
|
|||||||
services.AddScoped<IAuthorizationHandler, ServiceAccountAuthorizationHandler>();
|
services.AddScoped<IAuthorizationHandler, ServiceAccountAuthorizationHandler>();
|
||||||
services.AddScoped<IAuthorizationHandler, AccessPolicyAuthorizationHandler>();
|
services.AddScoped<IAuthorizationHandler, AccessPolicyAuthorizationHandler>();
|
||||||
services.AddScoped<IAccessClientQuery, AccessClientQuery>();
|
services.AddScoped<IAccessClientQuery, AccessClientQuery>();
|
||||||
|
services.AddScoped<IServiceAccountSecretsDetailsQuery, ServiceAccountSecretsDetailsQuery>();
|
||||||
services.AddScoped<ICreateSecretCommand, CreateSecretCommand>();
|
services.AddScoped<ICreateSecretCommand, CreateSecretCommand>();
|
||||||
services.AddScoped<IUpdateSecretCommand, UpdateSecretCommand>();
|
services.AddScoped<IUpdateSecretCommand, UpdateSecretCommand>();
|
||||||
services.AddScoped<IDeleteSecretCommand, DeleteSecretCommand>();
|
services.AddScoped<IDeleteSecretCommand, DeleteSecretCommand>();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.SecretsManager.Models.Data;
|
||||||
using Bit.Core.SecretsManager.Repositories;
|
using Bit.Core.SecretsManager.Repositories;
|
||||||
using Bit.Infrastructure.EntityFramework.Repositories;
|
using Bit.Infrastructure.EntityFramework.Repositories;
|
||||||
using Bit.Infrastructure.EntityFramework.SecretsManager.Models;
|
using Bit.Infrastructure.EntityFramework.SecretsManager.Models;
|
||||||
@ -140,6 +141,44 @@ public class ServiceAccountRepository : Repository<Core.SecretsManager.Entities.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<IEnumerable<ServiceAccountSecretsDetails>> GetManyByOrganizationIdWithSecretsDetailsAsync(
|
||||||
|
Guid organizationId, Guid userId, AccessClientType accessType)
|
||||||
|
{
|
||||||
|
using var scope = ServiceScopeFactory.CreateScope();
|
||||||
|
var dbContext = GetDatabaseContext(scope);
|
||||||
|
var query = from sa in dbContext.ServiceAccount
|
||||||
|
join ap in dbContext.ServiceAccountProjectAccessPolicy
|
||||||
|
on sa.Id equals ap.ServiceAccountId into grouping
|
||||||
|
from ap in grouping.DefaultIfEmpty()
|
||||||
|
where sa.OrganizationId == organizationId
|
||||||
|
select new
|
||||||
|
{
|
||||||
|
ServiceAccount = sa,
|
||||||
|
AccessToSecrets = ap.GrantedProject.Secrets.Count(s => s.DeletedDate == null)
|
||||||
|
};
|
||||||
|
|
||||||
|
query = accessType switch
|
||||||
|
{
|
||||||
|
AccessClientType.NoAccessCheck => query,
|
||||||
|
AccessClientType.User => query.Where(c =>
|
||||||
|
c.ServiceAccount.UserAccessPolicies.Any(ap => ap.OrganizationUser.User.Id == userId && ap.Read) ||
|
||||||
|
c.ServiceAccount.GroupAccessPolicies.Any(ap =>
|
||||||
|
ap.Group.GroupUsers.Any(gu => gu.OrganizationUser.User.Id == userId && ap.Read))),
|
||||||
|
_ => throw new ArgumentOutOfRangeException(nameof(accessType), accessType, null),
|
||||||
|
};
|
||||||
|
|
||||||
|
var results = (await query.ToListAsync())
|
||||||
|
.GroupBy(g => g.ServiceAccount)
|
||||||
|
.Select(g =>
|
||||||
|
new ServiceAccountSecretsDetails
|
||||||
|
{
|
||||||
|
ServiceAccount = Mapper.Map<Core.SecretsManager.Entities.ServiceAccount>(g.Key),
|
||||||
|
AccessToSecrets = g.Sum(x => x.AccessToSecrets),
|
||||||
|
}).OrderBy(c => c.ServiceAccount.RevisionDate).ToList();
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
private static Expression<Func<ServiceAccount, bool>> UserHasReadAccessToServiceAccount(Guid userId) => sa =>
|
private static Expression<Func<ServiceAccount, bool>> UserHasReadAccessToServiceAccount(Guid userId) => sa =>
|
||||||
sa.UserAccessPolicies.Any(ap => ap.OrganizationUser.User.Id == userId && ap.Read) ||
|
sa.UserAccessPolicies.Any(ap => ap.OrganizationUser.User.Id == userId && ap.Read) ||
|
||||||
sa.GroupAccessPolicies.Any(ap => ap.Group.GroupUsers.Any(gu => gu.OrganizationUser.User.Id == userId && ap.Read));
|
sa.GroupAccessPolicies.Any(ap => ap.Group.GroupUsers.Any(gu => gu.OrganizationUser.User.Id == userId && ap.Read));
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
using Bit.Commercial.Core.SecretsManager.Queries.ServiceAccounts;
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.SecretsManager.Entities;
|
||||||
|
using Bit.Core.SecretsManager.Models.Data;
|
||||||
|
using Bit.Core.SecretsManager.Repositories;
|
||||||
|
using Bit.Test.Common.AutoFixture;
|
||||||
|
using Bit.Test.Common.AutoFixture.Attributes;
|
||||||
|
using Bit.Test.Common.Helpers;
|
||||||
|
using NSubstitute;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace Bit.Commercial.Core.Test.SecretsManager.Queries.ServiceAccounts;
|
||||||
|
|
||||||
|
[SutProviderCustomize]
|
||||||
|
public class ServiceAccountSecretsDetailsQueryTests
|
||||||
|
{
|
||||||
|
[Theory]
|
||||||
|
[BitAutoData(false)]
|
||||||
|
[BitAutoData(true)]
|
||||||
|
public async Task GetManyByOrganizationId_CallsDifferentRepoMethods(
|
||||||
|
bool includeAccessToSecrets,
|
||||||
|
SutProvider<ServiceAccountSecretsDetailsQuery> sutProvider,
|
||||||
|
Guid organizationId,
|
||||||
|
Guid userId,
|
||||||
|
AccessClientType accessClient,
|
||||||
|
ServiceAccount mockSa,
|
||||||
|
ServiceAccountSecretsDetails mockSaDetails)
|
||||||
|
{
|
||||||
|
sutProvider.GetDependency<IServiceAccountRepository>().GetManyByOrganizationIdAsync(default, default, default)
|
||||||
|
.ReturnsForAnyArgs(new List<ServiceAccount> { mockSa });
|
||||||
|
|
||||||
|
sutProvider.GetDependency<IServiceAccountRepository>().GetManyByOrganizationIdWithSecretsDetailsAsync(default, default, default)
|
||||||
|
.ReturnsForAnyArgs(new List<ServiceAccountSecretsDetails> { mockSaDetails });
|
||||||
|
|
||||||
|
|
||||||
|
var result = await sutProvider.Sut.GetManyByOrganizationIdAsync(organizationId, userId, accessClient, includeAccessToSecrets);
|
||||||
|
|
||||||
|
if (includeAccessToSecrets)
|
||||||
|
{
|
||||||
|
await sutProvider.GetDependency<IServiceAccountRepository>().Received(1)
|
||||||
|
.GetManyByOrganizationIdWithSecretsDetailsAsync(Arg.Is(AssertHelper.AssertPropertyEqual(mockSaDetails.ServiceAccount.OrganizationId)),
|
||||||
|
Arg.Any<Guid>(), Arg.Any<AccessClientType>());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await sutProvider.GetDependency<IServiceAccountRepository>().Received(1)
|
||||||
|
.GetManyByOrganizationIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(mockSa.OrganizationId)),
|
||||||
|
Arg.Any<Guid>(), Arg.Any<AccessClientType>());
|
||||||
|
Assert.Equal(0, result.First().AccessToSecrets);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ using Bit.Core.SecretsManager.AuthorizationRequirements;
|
|||||||
using Bit.Core.SecretsManager.Commands.AccessTokens.Interfaces;
|
using Bit.Core.SecretsManager.Commands.AccessTokens.Interfaces;
|
||||||
using Bit.Core.SecretsManager.Commands.ServiceAccounts.Interfaces;
|
using Bit.Core.SecretsManager.Commands.ServiceAccounts.Interfaces;
|
||||||
using Bit.Core.SecretsManager.Entities;
|
using Bit.Core.SecretsManager.Entities;
|
||||||
|
using Bit.Core.SecretsManager.Queries.ServiceAccounts.Interfaces;
|
||||||
using Bit.Core.SecretsManager.Repositories;
|
using Bit.Core.SecretsManager.Repositories;
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
@ -26,6 +27,7 @@ public class ServiceAccountsController : Controller
|
|||||||
private readonly IAuthorizationService _authorizationService;
|
private readonly IAuthorizationService _authorizationService;
|
||||||
private readonly IServiceAccountRepository _serviceAccountRepository;
|
private readonly IServiceAccountRepository _serviceAccountRepository;
|
||||||
private readonly IApiKeyRepository _apiKeyRepository;
|
private readonly IApiKeyRepository _apiKeyRepository;
|
||||||
|
private readonly IServiceAccountSecretsDetailsQuery _serviceAccountSecretsDetailsQuery;
|
||||||
private readonly ICreateAccessTokenCommand _createAccessTokenCommand;
|
private readonly ICreateAccessTokenCommand _createAccessTokenCommand;
|
||||||
private readonly ICreateServiceAccountCommand _createServiceAccountCommand;
|
private readonly ICreateServiceAccountCommand _createServiceAccountCommand;
|
||||||
private readonly IUpdateServiceAccountCommand _updateServiceAccountCommand;
|
private readonly IUpdateServiceAccountCommand _updateServiceAccountCommand;
|
||||||
@ -38,6 +40,7 @@ public class ServiceAccountsController : Controller
|
|||||||
IAuthorizationService authorizationService,
|
IAuthorizationService authorizationService,
|
||||||
IServiceAccountRepository serviceAccountRepository,
|
IServiceAccountRepository serviceAccountRepository,
|
||||||
IApiKeyRepository apiKeyRepository,
|
IApiKeyRepository apiKeyRepository,
|
||||||
|
IServiceAccountSecretsDetailsQuery serviceAccountSecretsDetailsQuery,
|
||||||
ICreateAccessTokenCommand createAccessTokenCommand,
|
ICreateAccessTokenCommand createAccessTokenCommand,
|
||||||
ICreateServiceAccountCommand createServiceAccountCommand,
|
ICreateServiceAccountCommand createServiceAccountCommand,
|
||||||
IUpdateServiceAccountCommand updateServiceAccountCommand,
|
IUpdateServiceAccountCommand updateServiceAccountCommand,
|
||||||
@ -49,6 +52,7 @@ public class ServiceAccountsController : Controller
|
|||||||
_authorizationService = authorizationService;
|
_authorizationService = authorizationService;
|
||||||
_serviceAccountRepository = serviceAccountRepository;
|
_serviceAccountRepository = serviceAccountRepository;
|
||||||
_apiKeyRepository = apiKeyRepository;
|
_apiKeyRepository = apiKeyRepository;
|
||||||
|
_serviceAccountSecretsDetailsQuery = serviceAccountSecretsDetailsQuery;
|
||||||
_createServiceAccountCommand = createServiceAccountCommand;
|
_createServiceAccountCommand = createServiceAccountCommand;
|
||||||
_updateServiceAccountCommand = updateServiceAccountCommand;
|
_updateServiceAccountCommand = updateServiceAccountCommand;
|
||||||
_deleteServiceAccountsCommand = deleteServiceAccountsCommand;
|
_deleteServiceAccountsCommand = deleteServiceAccountsCommand;
|
||||||
@ -57,8 +61,8 @@ public class ServiceAccountsController : Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("/organizations/{organizationId}/service-accounts")]
|
[HttpGet("/organizations/{organizationId}/service-accounts")]
|
||||||
public async Task<ListResponseModel<ServiceAccountResponseModel>> ListByOrganizationAsync(
|
public async Task<ListResponseModel<ServiceAccountSecretsDetailsResponseModel>> ListByOrganizationAsync(
|
||||||
[FromRoute] Guid organizationId)
|
[FromRoute] Guid organizationId, [FromQuery] bool includeAccessToSecrets = false)
|
||||||
{
|
{
|
||||||
if (!_currentContext.AccessSecretsManager(organizationId))
|
if (!_currentContext.AccessSecretsManager(organizationId))
|
||||||
{
|
{
|
||||||
@ -69,11 +73,11 @@ public class ServiceAccountsController : Controller
|
|||||||
var orgAdmin = await _currentContext.OrganizationAdmin(organizationId);
|
var orgAdmin = await _currentContext.OrganizationAdmin(organizationId);
|
||||||
var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin);
|
var accessClient = AccessClientHelper.ToAccessClient(_currentContext.ClientType, orgAdmin);
|
||||||
|
|
||||||
var serviceAccounts =
|
var results =
|
||||||
await _serviceAccountRepository.GetManyByOrganizationIdAsync(organizationId, userId, accessClient);
|
await _serviceAccountSecretsDetailsQuery.GetManyByOrganizationIdAsync(organizationId, userId, accessClient,
|
||||||
|
includeAccessToSecrets);
|
||||||
var responses = serviceAccounts.Select(serviceAccount => new ServiceAccountResponseModel(serviceAccount));
|
var responses = results.Select(r => new ServiceAccountSecretsDetailsResponseModel(r));
|
||||||
return new ListResponseModel<ServiceAccountResponseModel>(responses);
|
return new ListResponseModel<ServiceAccountSecretsDetailsResponseModel>(responses);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{id}")]
|
[HttpGet("{id}")]
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Bit.Core.Models.Api;
|
using Bit.Core.Models.Api;
|
||||||
using Bit.Core.SecretsManager.Entities;
|
using Bit.Core.SecretsManager.Entities;
|
||||||
|
using Bit.Core.SecretsManager.Models.Data;
|
||||||
|
|
||||||
namespace Bit.Api.SecretsManager.Models.Response;
|
namespace Bit.Api.SecretsManager.Models.Response;
|
||||||
|
|
||||||
@ -35,3 +36,18 @@ public class ServiceAccountResponseModel : ResponseModel
|
|||||||
|
|
||||||
public DateTime RevisionDate { get; set; }
|
public DateTime RevisionDate { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ServiceAccountSecretsDetailsResponseModel : ServiceAccountResponseModel
|
||||||
|
{
|
||||||
|
public ServiceAccountSecretsDetailsResponseModel(ServiceAccountSecretsDetails serviceAccountDetails) : base(serviceAccountDetails.ServiceAccount)
|
||||||
|
{
|
||||||
|
if (serviceAccountDetails == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(serviceAccountDetails));
|
||||||
|
}
|
||||||
|
|
||||||
|
AccessToSecrets = serviceAccountDetails.AccessToSecrets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int AccessToSecrets { get; set; }
|
||||||
|
}
|
||||||
|
@ -0,0 +1,9 @@
|
|||||||
|
using Bit.Core.SecretsManager.Entities;
|
||||||
|
|
||||||
|
namespace Bit.Core.SecretsManager.Models.Data;
|
||||||
|
|
||||||
|
public class ServiceAccountSecretsDetails
|
||||||
|
{
|
||||||
|
public ServiceAccount ServiceAccount { get; set; }
|
||||||
|
public int AccessToSecrets { get; set; }
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
using Bit.Core.Enums;
|
||||||
|
using Bit.Core.SecretsManager.Models.Data;
|
||||||
|
|
||||||
|
namespace Bit.Core.SecretsManager.Queries.ServiceAccounts.Interfaces;
|
||||||
|
|
||||||
|
public interface IServiceAccountSecretsDetailsQuery
|
||||||
|
{
|
||||||
|
public Task<IEnumerable<ServiceAccountSecretsDetails>> GetManyByOrganizationIdAsync(
|
||||||
|
Guid organizationId, Guid userId, AccessClientType accessClient, bool includeAccessToSecrets);
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.SecretsManager.Entities;
|
using Bit.Core.SecretsManager.Entities;
|
||||||
|
using Bit.Core.SecretsManager.Models.Data;
|
||||||
|
|
||||||
namespace Bit.Core.SecretsManager.Repositories;
|
namespace Bit.Core.SecretsManager.Repositories;
|
||||||
|
|
||||||
@ -16,4 +17,5 @@ public interface IServiceAccountRepository
|
|||||||
Task<IEnumerable<ServiceAccount>> GetManyByOrganizationIdWriteAccessAsync(Guid organizationId, Guid userId, AccessClientType accessType);
|
Task<IEnumerable<ServiceAccount>> GetManyByOrganizationIdWriteAccessAsync(Guid organizationId, Guid userId, AccessClientType accessType);
|
||||||
Task<(bool Read, bool Write)> AccessToServiceAccountAsync(Guid id, Guid userId, AccessClientType accessType);
|
Task<(bool Read, bool Write)> AccessToServiceAccountAsync(Guid id, Guid userId, AccessClientType accessType);
|
||||||
Task<int> GetServiceAccountCountByOrganizationIdAsync(Guid organizationId);
|
Task<int> GetServiceAccountCountByOrganizationIdAsync(Guid organizationId);
|
||||||
|
Task<IEnumerable<ServiceAccountSecretsDetails>> GetManyByOrganizationIdWithSecretsDetailsAsync(Guid organizationId, Guid userId, AccessClientType accessType);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.SecretsManager.Entities;
|
using Bit.Core.SecretsManager.Entities;
|
||||||
|
using Bit.Core.SecretsManager.Models.Data;
|
||||||
|
|
||||||
namespace Bit.Core.SecretsManager.Repositories.Noop;
|
namespace Bit.Core.SecretsManager.Repositories.Noop;
|
||||||
|
|
||||||
@ -56,4 +57,6 @@ public class NoopServiceAccountRepository : IServiceAccountRepository
|
|||||||
{
|
{
|
||||||
return Task.FromResult(0);
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Task<IEnumerable<ServiceAccountSecretsDetails>> GetManyByOrganizationIdWithSecretsDetailsAsync(Guid organizationId, Guid userId, AccessClientType accessType) => throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ using Bit.Core.SecretsManager.Commands.AccessTokens.Interfaces;
|
|||||||
using Bit.Core.SecretsManager.Commands.ServiceAccounts.Interfaces;
|
using Bit.Core.SecretsManager.Commands.ServiceAccounts.Interfaces;
|
||||||
using Bit.Core.SecretsManager.Entities;
|
using Bit.Core.SecretsManager.Entities;
|
||||||
using Bit.Core.SecretsManager.Models.Data;
|
using Bit.Core.SecretsManager.Models.Data;
|
||||||
|
using Bit.Core.SecretsManager.Queries.ServiceAccounts.Interfaces;
|
||||||
using Bit.Core.SecretsManager.Repositories;
|
using Bit.Core.SecretsManager.Repositories;
|
||||||
using Bit.Core.Services;
|
using Bit.Core.Services;
|
||||||
using Bit.Test.Common.AutoFixture;
|
using Bit.Test.Common.AutoFixture;
|
||||||
@ -33,9 +34,9 @@ public class ServiceAccountsControllerTests
|
|||||||
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
|
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
|
||||||
var result = await sutProvider.Sut.ListByOrganizationAsync(id);
|
var result = await sutProvider.Sut.ListByOrganizationAsync(id);
|
||||||
|
|
||||||
await sutProvider.GetDependency<IServiceAccountRepository>().Received(1)
|
await sutProvider.GetDependency<IServiceAccountSecretsDetailsQuery>().Received(1)
|
||||||
.GetManyByOrganizationIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(id)), Arg.Any<Guid>(),
|
.GetManyByOrganizationIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(id)),
|
||||||
Arg.Any<AccessClientType>());
|
Arg.Any<Guid>(), Arg.Any<AccessClientType>(), Arg.Any<bool>());
|
||||||
|
|
||||||
Assert.Empty(result.Data);
|
Assert.Empty(result.Data);
|
||||||
}
|
}
|
||||||
@ -43,18 +44,18 @@ public class ServiceAccountsControllerTests
|
|||||||
[Theory]
|
[Theory]
|
||||||
[BitAutoData]
|
[BitAutoData]
|
||||||
public async void GetServiceAccountsByOrganization_Success(SutProvider<ServiceAccountsController> sutProvider,
|
public async void GetServiceAccountsByOrganization_Success(SutProvider<ServiceAccountsController> sutProvider,
|
||||||
ServiceAccount resultServiceAccount)
|
ServiceAccountSecretsDetails resultServiceAccount)
|
||||||
{
|
{
|
||||||
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(default).ReturnsForAnyArgs(true);
|
sutProvider.GetDependency<ICurrentContext>().AccessSecretsManager(default).ReturnsForAnyArgs(true);
|
||||||
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
|
sutProvider.GetDependency<IUserService>().GetProperUserId(default).ReturnsForAnyArgs(Guid.NewGuid());
|
||||||
sutProvider.GetDependency<IServiceAccountRepository>().GetManyByOrganizationIdAsync(default, default, default)
|
sutProvider.GetDependency<IServiceAccountSecretsDetailsQuery>().GetManyByOrganizationIdAsync(default, default, default, default)
|
||||||
.ReturnsForAnyArgs(new List<ServiceAccount> { resultServiceAccount });
|
.ReturnsForAnyArgs(new List<ServiceAccountSecretsDetails> { resultServiceAccount });
|
||||||
|
|
||||||
var result = await sutProvider.Sut.ListByOrganizationAsync(resultServiceAccount.OrganizationId);
|
var result = await sutProvider.Sut.ListByOrganizationAsync(resultServiceAccount.ServiceAccount.OrganizationId);
|
||||||
|
|
||||||
await sutProvider.GetDependency<IServiceAccountRepository>().Received(1)
|
await sutProvider.GetDependency<IServiceAccountSecretsDetailsQuery>().Received(1)
|
||||||
.GetManyByOrganizationIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(resultServiceAccount.OrganizationId)),
|
.GetManyByOrganizationIdAsync(Arg.Is(AssertHelper.AssertPropertyEqual(resultServiceAccount.ServiceAccount.OrganizationId)),
|
||||||
Arg.Any<Guid>(), Arg.Any<AccessClientType>());
|
Arg.Any<Guid>(), Arg.Any<AccessClientType>(), Arg.Any<bool>());
|
||||||
Assert.NotEmpty(result.Data);
|
Assert.NotEmpty(result.Data);
|
||||||
Assert.Single(result.Data);
|
Assert.Single(result.Data);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user