Browse Source

[SG-841] Refactor GetOrganizationApiKeyCommand (#2436)

* Renamed and split up class to only query for an organization key

* Added a command class to create an organization api key

* Updated service registration and controller to include new changes

* Updated test cases to reflect refactor

* fixed lint issues

* Fixed PR comment
pull/2448/head
Gbubemi Smith 3 years ago committed by GitHub
parent
commit
f74730dd2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 19
      src/Api/Controllers/OrganizationsController.cs
  2. 32
      src/Core/OrganizationFeatures/OrganizationApiKeys/CreateOrganizationApiKeyCommand.cs
  3. 19
      src/Core/OrganizationFeatures/OrganizationApiKeys/GetOrganizationApiKeyQuery.cs
  4. 9
      src/Core/OrganizationFeatures/OrganizationApiKeys/Interfaces/ICreateOrganizationApiKeyCommand.cs
  5. 2
      src/Core/OrganizationFeatures/OrganizationApiKeys/Interfaces/IGetOrganizationApiKeyQuery.cs
  6. 7
      src/Core/OrganizationFeatures/OrganizationServiceCollectionExtensions.cs
  7. 10
      test/Api.Test/Controllers/OrganizationsControllerTests.cs
  8. 27
      test/Core.Test/OrganizationFeatures/OrganizationApiKeys/CreateOrganizationApiKeyCommandTest.cs
  9. 27
      test/Core.Test/OrganizationFeatures/OrganizationApiKeys/GetOrganizationApiKeyQueryTests.cs

19
src/Api/Controllers/OrganizationsController.cs

@ -33,8 +33,9 @@ public class OrganizationsController : Controller @@ -33,8 +33,9 @@ public class OrganizationsController : Controller
private readonly ICurrentContext _currentContext;
private readonly ISsoConfigRepository _ssoConfigRepository;
private readonly ISsoConfigService _ssoConfigService;
private readonly IGetOrganizationApiKeyCommand _getOrganizationApiKeyCommand;
private readonly IGetOrganizationApiKeyQuery _getOrganizationApiKeyQuery;
private readonly IRotateOrganizationApiKeyCommand _rotateOrganizationApiKeyCommand;
private readonly ICreateOrganizationApiKeyCommand _createOrganizationApiKeyCommand;
private readonly IOrganizationApiKeyRepository _organizationApiKeyRepository;
private readonly GlobalSettings _globalSettings;
@ -48,8 +49,9 @@ public class OrganizationsController : Controller @@ -48,8 +49,9 @@ public class OrganizationsController : Controller
ICurrentContext currentContext,
ISsoConfigRepository ssoConfigRepository,
ISsoConfigService ssoConfigService,
IGetOrganizationApiKeyCommand getOrganizationApiKeyCommand,
IGetOrganizationApiKeyQuery getOrganizationApiKeyQuery,
IRotateOrganizationApiKeyCommand rotateOrganizationApiKeyCommand,
ICreateOrganizationApiKeyCommand createOrganizationApiKeyCommand,
IOrganizationApiKeyRepository organizationApiKeyRepository,
GlobalSettings globalSettings)
{
@ -62,8 +64,9 @@ public class OrganizationsController : Controller @@ -62,8 +64,9 @@ public class OrganizationsController : Controller
_currentContext = currentContext;
_ssoConfigRepository = ssoConfigRepository;
_ssoConfigService = ssoConfigService;
_getOrganizationApiKeyCommand = getOrganizationApiKeyCommand;
_getOrganizationApiKeyQuery = getOrganizationApiKeyQuery;
_rotateOrganizationApiKeyCommand = rotateOrganizationApiKeyCommand;
_createOrganizationApiKeyCommand = createOrganizationApiKeyCommand;
_organizationApiKeyRepository = organizationApiKeyRepository;
_globalSettings = globalSettings;
}
@ -514,8 +517,9 @@ public class OrganizationsController : Controller @@ -514,8 +517,9 @@ public class OrganizationsController : Controller
}
}
var organizationApiKey = await _getOrganizationApiKeyCommand
.GetOrganizationApiKeyAsync(organization.Id, model.Type);
var organizationApiKey = await _getOrganizationApiKeyQuery
.GetOrganizationApiKeyAsync(organization.Id, model.Type) ??
await _createOrganizationApiKeyCommand.CreateAsync(organization.Id, model.Type);
var user = await _userService.GetUserByPrincipalAsync(User);
if (user == null)
@ -565,8 +569,9 @@ public class OrganizationsController : Controller @@ -565,8 +569,9 @@ public class OrganizationsController : Controller
throw new NotFoundException();
}
var organizationApiKey = await _getOrganizationApiKeyCommand
.GetOrganizationApiKeyAsync(organization.Id, model.Type);
var organizationApiKey = await _getOrganizationApiKeyQuery
.GetOrganizationApiKeyAsync(organization.Id, model.Type) ??
await _createOrganizationApiKeyCommand.CreateAsync(organization.Id, model.Type);
var user = await _userService.GetUserByPrincipalAsync(User);
if (user == null)

32
src/Core/OrganizationFeatures/OrganizationApiKeys/CreateOrganizationApiKeyCommand.cs

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.OrganizationFeatures.OrganizationApiKeys.Interfaces;
using Bit.Core.Repositories;
using Bit.Core.Utilities;
namespace Bit.Core.OrganizationFeatures.OrganizationApiKeys;
public class CreateOrganizationApiKeyCommand : ICreateOrganizationApiKeyCommand
{
private readonly IOrganizationApiKeyRepository _organizationApiKeyRepository;
public CreateOrganizationApiKeyCommand(IOrganizationApiKeyRepository organizationApiKeyRepository)
{
_organizationApiKeyRepository = organizationApiKeyRepository;
}
public async Task<OrganizationApiKey> CreateAsync(Guid organizationId,
OrganizationApiKeyType organizationApiKeyType)
{
var apiKey = new OrganizationApiKey
{
OrganizationId = organizationId,
Type = organizationApiKeyType,
ApiKey = CoreHelpers.SecureRandomString(30),
RevisionDate = DateTime.UtcNow,
};
await _organizationApiKeyRepository.CreateAsync(apiKey);
return apiKey;
}
}

19
src/Core/OrganizationFeatures/OrganizationApiKeys/GetOrganizationApiKeyCommand.cs → src/Core/OrganizationFeatures/OrganizationApiKeys/GetOrganizationApiKeyQuery.cs

@ -2,15 +2,14 @@ @@ -2,15 +2,14 @@
using Bit.Core.Enums;
using Bit.Core.OrganizationFeatures.OrganizationApiKeys.Interfaces;
using Bit.Core.Repositories;
using Bit.Core.Utilities;
namespace Bit.Core.OrganizationFeatures.OrganizationApiKeys;
public class GetOrganizationApiKeyCommand : IGetOrganizationApiKeyCommand
public class GetOrganizationApiKeyQuery : IGetOrganizationApiKeyQuery
{
private readonly IOrganizationApiKeyRepository _organizationApiKeyRepository;
public GetOrganizationApiKeyCommand(IOrganizationApiKeyRepository organizationApiKeyRepository)
public GetOrganizationApiKeyQuery(IOrganizationApiKeyRepository organizationApiKeyRepository)
{
_organizationApiKeyRepository = organizationApiKeyRepository;
}
@ -25,20 +24,6 @@ public class GetOrganizationApiKeyCommand : IGetOrganizationApiKeyCommand @@ -25,20 +24,6 @@ public class GetOrganizationApiKeyCommand : IGetOrganizationApiKeyCommand
var apiKeys = await _organizationApiKeyRepository
.GetManyByOrganizationIdTypeAsync(organizationId, organizationApiKeyType);
if (apiKeys == null || !apiKeys.Any())
{
var apiKey = new OrganizationApiKey
{
OrganizationId = organizationId,
Type = organizationApiKeyType,
ApiKey = CoreHelpers.SecureRandomString(30),
RevisionDate = DateTime.UtcNow,
};
await _organizationApiKeyRepository.CreateAsync(apiKey);
return apiKey;
}
// NOTE: Currently we only allow one type of api key per organization
return apiKeys.Single();
}

9
src/Core/OrganizationFeatures/OrganizationApiKeys/Interfaces/ICreateOrganizationApiKeyCommand.cs

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
namespace Bit.Core.OrganizationFeatures.OrganizationApiKeys.Interfaces;
public interface ICreateOrganizationApiKeyCommand
{
Task<OrganizationApiKey> CreateAsync(Guid organizationId, OrganizationApiKeyType organizationApiKeyType);
}

2
src/Core/OrganizationFeatures/OrganizationApiKeys/Interfaces/IGetOrganizationApiKeyCommand.cs → src/Core/OrganizationFeatures/OrganizationApiKeys/Interfaces/IGetOrganizationApiKeyQuery.cs

@ -3,7 +3,7 @@ using Bit.Core.Enums; @@ -3,7 +3,7 @@ using Bit.Core.Enums;
namespace Bit.Core.OrganizationFeatures.OrganizationApiKeys.Interfaces;
public interface IGetOrganizationApiKeyCommand
public interface IGetOrganizationApiKeyQuery
{
Task<OrganizationApiKey> GetOrganizationApiKeyAsync(Guid organizationId, OrganizationApiKeyType organizationApiKeyType);
}

7
src/Core/OrganizationFeatures/OrganizationServiceCollectionExtensions.cs

@ -24,7 +24,7 @@ public static class OrganizationServiceCollectionExtensions @@ -24,7 +24,7 @@ public static class OrganizationServiceCollectionExtensions
services.AddTokenizers();
services.AddOrganizationConnectionCommands();
services.AddOrganizationSponsorshipCommands(globalSettings);
services.AddOrganizationApiKeyCommands();
services.AddOrganizationApiKeyCommandsQueries();
}
private static void AddOrganizationConnectionCommands(this IServiceCollection services)
@ -59,10 +59,11 @@ public static class OrganizationServiceCollectionExtensions @@ -59,10 +59,11 @@ public static class OrganizationServiceCollectionExtensions
}
}
private static void AddOrganizationApiKeyCommands(this IServiceCollection services)
private static void AddOrganizationApiKeyCommandsQueries(this IServiceCollection services)
{
services.AddScoped<IGetOrganizationApiKeyCommand, GetOrganizationApiKeyCommand>();
services.AddScoped<IGetOrganizationApiKeyQuery, GetOrganizationApiKeyQuery>();
services.AddScoped<IRotateOrganizationApiKeyCommand, RotateOrganizationApiKeyCommand>();
services.AddScoped<ICreateOrganizationApiKeyCommand, CreateOrganizationApiKeyCommand>();
}
private static void AddTokenizers(this IServiceCollection services)

10
test/Api.Test/Controllers/OrganizationsControllerTests.cs

@ -26,9 +26,10 @@ public class OrganizationsControllerTests : IDisposable @@ -26,9 +26,10 @@ public class OrganizationsControllerTests : IDisposable
private readonly ISsoConfigRepository _ssoConfigRepository;
private readonly ISsoConfigService _ssoConfigService;
private readonly IUserService _userService;
private readonly IGetOrganizationApiKeyCommand _getOrganizationApiKeyCommand;
private readonly IGetOrganizationApiKeyQuery _getOrganizationApiKeyQuery;
private readonly IRotateOrganizationApiKeyCommand _rotateOrganizationApiKeyCommand;
private readonly IOrganizationApiKeyRepository _organizationApiKeyRepository;
private readonly ICreateOrganizationApiKeyCommand _createOrganizationApiKeyCommand;
private readonly OrganizationsController _sut;
@ -43,15 +44,16 @@ public class OrganizationsControllerTests : IDisposable @@ -43,15 +44,16 @@ public class OrganizationsControllerTests : IDisposable
_policyRepository = Substitute.For<IPolicyRepository>();
_ssoConfigRepository = Substitute.For<ISsoConfigRepository>();
_ssoConfigService = Substitute.For<ISsoConfigService>();
_getOrganizationApiKeyCommand = Substitute.For<IGetOrganizationApiKeyCommand>();
_getOrganizationApiKeyQuery = Substitute.For<IGetOrganizationApiKeyQuery>();
_rotateOrganizationApiKeyCommand = Substitute.For<IRotateOrganizationApiKeyCommand>();
_organizationApiKeyRepository = Substitute.For<IOrganizationApiKeyRepository>();
_userService = Substitute.For<IUserService>();
_createOrganizationApiKeyCommand = Substitute.For<ICreateOrganizationApiKeyCommand>();
_sut = new OrganizationsController(_organizationRepository, _organizationUserRepository,
_policyRepository, _organizationService, _userService, _paymentService, _currentContext,
_ssoConfigRepository, _ssoConfigService, _getOrganizationApiKeyCommand, _rotateOrganizationApiKeyCommand,
_organizationApiKeyRepository, _globalSettings);
_ssoConfigRepository, _ssoConfigService, _getOrganizationApiKeyQuery, _rotateOrganizationApiKeyCommand,
_createOrganizationApiKeyCommand, _organizationApiKeyRepository, _globalSettings);
}
public void Dispose()

27
test/Core.Test/OrganizationFeatures/OrganizationApiKeys/CreateOrganizationApiKeyCommandTest.cs

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.OrganizationFeatures.OrganizationApiKeys;
using Bit.Core.Repositories;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using NSubstitute;
using NSubstitute.ReceivedExtensions;
using Xunit;
namespace Bit.Core.Test.OrganizationFeatures.OrganizationApiKeys;
[SutProviderCustomize]
public class CreateOrganizationApiKeyCommandTest
{
[Theory]
[BitAutoData]
public async Task CreateAsync_CreatesOrganizationApiKey(SutProvider<CreateOrganizationApiKeyCommand> sutProvider,
Guid organizationId, OrganizationApiKeyType keyType)
{
await sutProvider.Sut.CreateAsync(organizationId, keyType);
await sutProvider.GetDependency<IOrganizationApiKeyRepository>().Received(1)
.CreateAsync(Arg.Is<OrganizationApiKey>(o => o.OrganizationId == organizationId
&& o.Type == keyType));
}
}

27
test/Core.Test/OrganizationFeatures/OrganizationApiKeys/GetOrganizationApiKeyCommandTests.cs → test/Core.Test/OrganizationFeatures/OrganizationApiKeys/GetOrganizationApiKeyQueryTests.cs

@ -10,11 +10,11 @@ using Xunit; @@ -10,11 +10,11 @@ using Xunit;
namespace Bit.Core.Test.OrganizationFeatures.OrganizationApiKeys;
[SutProviderCustomize]
public class GetOrganizationApiKeyCommandTests
public class GetOrganizationApiKeyQueryTests
{
[Theory]
[BitAutoData]
public async Task GetOrganizationApiKey_HasOne_Returns(SutProvider<GetOrganizationApiKeyCommand> sutProvider,
public async Task GetOrganizationApiKey_HasOne_Returns(SutProvider<GetOrganizationApiKeyQuery> sutProvider,
Guid id, Guid organizationId, OrganizationApiKeyType keyType)
{
sutProvider.GetDependency<IOrganizationApiKeyRepository>()
@ -38,7 +38,7 @@ public class GetOrganizationApiKeyCommandTests @@ -38,7 +38,7 @@ public class GetOrganizationApiKeyCommandTests
[Theory]
[BitAutoData]
public async Task GetOrganizationApiKey_HasTwo_Throws(SutProvider<GetOrganizationApiKeyCommand> sutProvider,
public async Task GetOrganizationApiKey_HasTwo_Throws(SutProvider<GetOrganizationApiKeyQuery> sutProvider,
Guid organizationId, OrganizationApiKeyType keyType)
{
sutProvider.GetDependency<IOrganizationApiKeyRepository>()
@ -69,26 +69,7 @@ public class GetOrganizationApiKeyCommandTests @@ -69,26 +69,7 @@ public class GetOrganizationApiKeyCommandTests
[Theory]
[BitAutoData]
public async Task GetOrganizationApiKey_HasNone_CreatesAndReturns(SutProvider<GetOrganizationApiKeyCommand> sutProvider,
Guid organizationId, OrganizationApiKeyType keyType)
{
sutProvider.GetDependency<IOrganizationApiKeyRepository>()
.GetManyByOrganizationIdTypeAsync(organizationId, keyType)
.Returns(Enumerable.Empty<OrganizationApiKey>());
var apiKey = await sutProvider.Sut.GetOrganizationApiKeyAsync(organizationId, keyType);
Assert.NotNull(apiKey);
Assert.Equal(organizationId, apiKey.OrganizationId);
Assert.Equal(keyType, apiKey.Type);
await sutProvider.GetDependency<IOrganizationApiKeyRepository>()
.Received(1)
.CreateAsync(Arg.Any<OrganizationApiKey>());
}
[Theory]
[BitAutoData]
public async Task GetOrganizationApiKey_BadType_Throws(SutProvider<GetOrganizationApiKeyCommand> sutProvider,
public async Task GetOrganizationApiKey_BadType_Throws(SutProvider<GetOrganizationApiKeyQuery> sutProvider,
Guid organizationId, OrganizationApiKeyType keyType)
{
keyType = (OrganizationApiKeyType)byte.MaxValue;
Loading…
Cancel
Save