mirror of
https://github.com/bitwarden/server.git
synced 2025-07-01 08:02:49 -05:00
[EC-826] Merge license sync feature branch to master (#2587)
* [EC-634] Extract GenerateLicenseAsync to a query (#2373) * [EC-637] Add license sync to server (#2453) * [EC-1036] Show correct license sync date (#2626) * Update method name per new pattern
This commit is contained in:
@ -1,14 +1,14 @@
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud;
|
||||
using Bit.Core.OrganizationFeatures.OrganizationConnections;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.Cloud;
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationConnections;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class ValidateBillingSyncKeyCommandTests
|
@ -0,0 +1,64 @@
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Enums;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Business;
|
||||
using Bit.Core.OrganizationFeatures.OrganizationLicenses;
|
||||
using Bit.Core.Repositories;
|
||||
using Bit.Core.Services;
|
||||
using Bit.Core.Test.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using NSubstitute.ReturnsExtensions;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationLicenses;
|
||||
|
||||
[SubscriptionInfoCustomize]
|
||||
[OrganizationLicenseCustomize]
|
||||
[SutProviderCustomize]
|
||||
public class CloudGetOrganizationLicenseQueryTests
|
||||
{
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetLicenseAsync_InvalidInstallationId_Throws(SutProvider<CloudGetOrganizationLicenseQuery> sutProvider,
|
||||
Organization organization, Guid installationId, int version)
|
||||
{
|
||||
sutProvider.GetDependency<IInstallationRepository>().GetByIdAsync(installationId).ReturnsNull();
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
async () => await sutProvider.Sut.GetLicenseAsync(organization, installationId, version));
|
||||
Assert.Contains("Invalid installation id", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetLicenseAsync_DisabledOrganization_Throws(SutProvider<CloudGetOrganizationLicenseQuery> sutProvider,
|
||||
Organization organization, Guid installationId, Installation installation)
|
||||
{
|
||||
installation.Enabled = false;
|
||||
sutProvider.GetDependency<IInstallationRepository>().GetByIdAsync(installationId).Returns(installation);
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(
|
||||
async () => await sutProvider.Sut.GetLicenseAsync(organization, installationId));
|
||||
Assert.Contains("Invalid installation id", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task GetLicenseAsync_CreatesAndReturns(SutProvider<CloudGetOrganizationLicenseQuery> sutProvider,
|
||||
Organization organization, Guid installationId, Installation installation, SubscriptionInfo subInfo,
|
||||
byte[] licenseSignature)
|
||||
{
|
||||
installation.Enabled = true;
|
||||
sutProvider.GetDependency<IInstallationRepository>().GetByIdAsync(installationId).Returns(installation);
|
||||
sutProvider.GetDependency<IPaymentService>().GetSubscriptionAsync(organization).Returns(subInfo);
|
||||
sutProvider.GetDependency<ILicensingService>().SignLicense(Arg.Any<ILicense>()).Returns(licenseSignature);
|
||||
|
||||
var result = await sutProvider.Sut.GetLicenseAsync(organization, installationId);
|
||||
|
||||
Assert.Equal(LicenseType.Organization, result.LicenseType);
|
||||
Assert.Equal(organization.Id, result.Id);
|
||||
Assert.Equal(installationId, result.InstallationId);
|
||||
Assert.Equal(licenseSignature, result.SignatureBytes);
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
using System.Text.Json;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Business;
|
||||
using Bit.Core.Models.OrganizationConnectionConfigs;
|
||||
using Bit.Core.OrganizationFeatures.OrganizationLicenses;
|
||||
using Bit.Core.Settings;
|
||||
using Bit.Core.Test.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using Bit.Test.Common.Helpers;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationLicenses;
|
||||
|
||||
[SutProviderCustomize]
|
||||
public class SelfHostedGetOrganizationLicenseQueryTests
|
||||
{
|
||||
private static SutProvider<SelfHostedGetOrganizationLicenseQuery> GetSutProvider(BillingSyncConfig config,
|
||||
string apiResponse = null)
|
||||
{
|
||||
return new SutProvider<SelfHostedGetOrganizationLicenseQuery>()
|
||||
.ConfigureBaseIdentityClientService($"licenses/organization/{config.CloudOrganizationId}",
|
||||
HttpMethod.Get, apiResponse: apiResponse);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
[OrganizationLicenseCustomize]
|
||||
public async void GetLicenseAsync_Success(Organization organization,
|
||||
OrganizationConnection<BillingSyncConfig> billingSyncConnection, BillingSyncConfig config, OrganizationLicense license)
|
||||
{
|
||||
var sutProvider = GetSutProvider(config, JsonSerializer.Serialize(license));
|
||||
billingSyncConnection.Enabled = true;
|
||||
billingSyncConnection.Config = config;
|
||||
|
||||
var result = await sutProvider.Sut.GetLicenseAsync(organization, billingSyncConnection);
|
||||
AssertHelper.AssertPropertyEqual(result, license);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void GetLicenseAsync_WhenNotSelfHosted_Throws(Organization organization,
|
||||
OrganizationConnection billingSyncConnection, BillingSyncConfig config)
|
||||
{
|
||||
var sutProvider = GetSutProvider(config);
|
||||
sutProvider.GetDependency<IGlobalSettings>().SelfHosted = false;
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.GetLicenseAsync(organization, billingSyncConnection));
|
||||
Assert.Contains("only available for self-hosted", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void GetLicenseAsync_WhenCloudCommunicationDisabled_Throws(Organization organization,
|
||||
OrganizationConnection billingSyncConnection, BillingSyncConfig config)
|
||||
{
|
||||
var sutProvider = GetSutProvider(config);
|
||||
sutProvider.GetDependency<IGlobalSettings>().EnableCloudCommunication = false;
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.GetLicenseAsync(organization, billingSyncConnection));
|
||||
Assert.Contains("Cloud communication is disabled", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void GetLicenseAsync_WhenCantUseConnection_Throws(Organization organization,
|
||||
OrganizationConnection<BillingSyncConfig> billingSyncConnection, BillingSyncConfig config)
|
||||
{
|
||||
var sutProvider = GetSutProvider(config);
|
||||
billingSyncConnection.Enabled = false;
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.GetLicenseAsync(organization, billingSyncConnection));
|
||||
Assert.Contains("Connection disabled", exception.Message);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async void GetLicenseAsync_WhenNullResponse_Throws(Organization organization,
|
||||
OrganizationConnection<BillingSyncConfig> billingSyncConnection, BillingSyncConfig config)
|
||||
{
|
||||
var sutProvider = GetSutProvider(config);
|
||||
billingSyncConnection.Enabled = true;
|
||||
billingSyncConnection.Config = config;
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.GetLicenseAsync(organization, billingSyncConnection));
|
||||
Assert.Contains("An error has occurred. Check your internet connection and ensure the billing token is correct.",
|
||||
exception.Message);
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
using System.Text.Json;
|
||||
using AutoFixture;
|
||||
using Bit.Core.Entities;
|
||||
using Bit.Core.Exceptions;
|
||||
using Bit.Core.Models.Api.Response.OrganizationSponsorships;
|
||||
@ -12,55 +11,22 @@ using Bit.Core.Test.AutoFixture.OrganizationSponsorshipFixtures;
|
||||
using Bit.Test.Common.AutoFixture;
|
||||
using Bit.Test.Common.AutoFixture.Attributes;
|
||||
using NSubstitute;
|
||||
using RichardSzalay.MockHttp;
|
||||
using Xunit;
|
||||
|
||||
namespace Bit.Core.Test.OrganizationFeatures.OrganizationSponsorships.FamiliesForEnterprise.SelfHosted;
|
||||
|
||||
public class SelfHostedSyncSponsorshipsCommandTests : FamiliesForEnterpriseTestsBase
|
||||
{
|
||||
|
||||
public static SutProvider<SelfHostedSyncSponsorshipsCommand> GetSutProvider(bool enableCloudCommunication = true, string identityResponse = null, string apiResponse = null)
|
||||
private static SutProvider<SelfHostedSyncSponsorshipsCommand> GetSutProvider(string apiResponse = null)
|
||||
{
|
||||
var fixture = new Fixture().WithAutoNSubstitutionsAutoPopulatedProperties();
|
||||
fixture.AddMockHttp();
|
||||
|
||||
var settings = fixture.Create<IGlobalSettings>();
|
||||
settings.SelfHosted = true;
|
||||
settings.EnableCloudCommunication = enableCloudCommunication;
|
||||
|
||||
var apiUri = fixture.Create<Uri>();
|
||||
var identityUri = fixture.Create<Uri>();
|
||||
settings.Installation.ApiUri.Returns(apiUri.ToString());
|
||||
settings.Installation.IdentityUri.Returns(identityUri.ToString());
|
||||
|
||||
var apiHandler = new MockHttpMessageHandler();
|
||||
var identityHandler = new MockHttpMessageHandler();
|
||||
var syncUri = string.Concat(apiUri, "organization/sponsorship/sync");
|
||||
var tokenUri = string.Concat(identityUri, "connect/token");
|
||||
|
||||
apiHandler.When(HttpMethod.Post, syncUri)
|
||||
.Respond("application/json", apiResponse);
|
||||
identityHandler.When(HttpMethod.Post, tokenUri)
|
||||
.Respond("application/json", identityResponse ?? "{\"access_token\":\"string\",\"expires_in\":3600,\"token_type\":\"Bearer\",\"scope\":\"string\"}");
|
||||
|
||||
|
||||
var apiHttp = apiHandler.ToHttpClient();
|
||||
var identityHttp = identityHandler.ToHttpClient();
|
||||
|
||||
var mockHttpClientFactory = Substitute.For<IHttpClientFactory>();
|
||||
mockHttpClientFactory.CreateClient(Arg.Is("client")).Returns(apiHttp);
|
||||
mockHttpClientFactory.CreateClient(Arg.Is("identity")).Returns(identityHttp);
|
||||
|
||||
return new SutProvider<SelfHostedSyncSponsorshipsCommand>(fixture)
|
||||
.SetDependency(settings)
|
||||
.SetDependency(mockHttpClientFactory)
|
||||
.Create();
|
||||
return new SutProvider<SelfHostedSyncSponsorshipsCommand>()
|
||||
.ConfigureBaseIdentityClientService("organization/sponsorship/sync",
|
||||
HttpMethod.Post, apiResponse: apiResponse);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_BillingSyncKeyDisabled_ThrowsBadRequest(
|
||||
public async Task SyncOrganization_BillingSyncConnectionDisabled_ThrowsBadRequest(
|
||||
Guid cloudOrganizationId, OrganizationConnection billingSyncConnection)
|
||||
{
|
||||
var sutProvider = GetSutProvider();
|
||||
@ -73,7 +39,7 @@ public class SelfHostedSyncSponsorshipsCommandTests : FamiliesForEnterpriseTests
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SyncOrganization(billingSyncConnection.OrganizationId, cloudOrganizationId, billingSyncConnection));
|
||||
|
||||
Assert.Contains($"Billing Sync Key disabled", exception.Message);
|
||||
Assert.Contains($"Connection disabled", exception.Message);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
@ -85,7 +51,7 @@ public class SelfHostedSyncSponsorshipsCommandTests : FamiliesForEnterpriseTests
|
||||
|
||||
[Theory]
|
||||
[BitAutoData]
|
||||
public async Task SyncOrganization_BillingSyncKeyEmpty_ThrowsBadRequest(
|
||||
public async Task SyncOrganization_BillingSyncConfigEmpty_ThrowsBadRequest(
|
||||
Guid cloudOrganizationId, OrganizationConnection billingSyncConnection)
|
||||
{
|
||||
var sutProvider = GetSutProvider();
|
||||
@ -94,7 +60,7 @@ public class SelfHostedSyncSponsorshipsCommandTests : FamiliesForEnterpriseTests
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SyncOrganization(billingSyncConnection.OrganizationId, cloudOrganizationId, billingSyncConnection));
|
||||
|
||||
Assert.Contains($"No Billing Sync Key known", exception.Message);
|
||||
Assert.Contains($"No saved Connection config", exception.Message);
|
||||
|
||||
await sutProvider.GetDependency<IOrganizationSponsorshipRepository>()
|
||||
.DidNotReceiveWithAnyArgs()
|
||||
@ -109,7 +75,8 @@ public class SelfHostedSyncSponsorshipsCommandTests : FamiliesForEnterpriseTests
|
||||
public async Task SyncOrganization_CloudCommunicationDisabled_EarlyReturn(
|
||||
Guid cloudOrganizationId, OrganizationConnection billingSyncConnection)
|
||||
{
|
||||
var sutProvider = GetSutProvider(false);
|
||||
var sutProvider = GetSutProvider();
|
||||
sutProvider.GetDependency<IGlobalSettings>().EnableCloudCommunication = false;
|
||||
|
||||
var exception = await Assert.ThrowsAsync<BadRequestException>(() =>
|
||||
sutProvider.Sut.SyncOrganization(billingSyncConnection.OrganizationId, cloudOrganizationId, billingSyncConnection));
|
||||
@ -136,7 +103,8 @@ public class SelfHostedSyncSponsorshipsCommandTests : FamiliesForEnterpriseTests
|
||||
SponsorshipsBatch = sponsorships.Select(o => new OrganizationSponsorshipData(o))
|
||||
}));
|
||||
|
||||
var sutProvider = GetSutProvider(apiResponse: syncJsonResponse);
|
||||
var sutProvider = GetSutProvider(syncJsonResponse);
|
||||
|
||||
billingSyncConnection.SetConfig(new BillingSyncConfig
|
||||
{
|
||||
BillingSyncKey = "okslkcslkjf"
|
||||
@ -166,7 +134,7 @@ public class SelfHostedSyncSponsorshipsCommandTests : FamiliesForEnterpriseTests
|
||||
SponsorshipsBatch = sponsorships.Select(o => new OrganizationSponsorshipData(o) { CloudSponsorshipRemoved = true })
|
||||
}));
|
||||
|
||||
var sutProvider = GetSutProvider(apiResponse: syncJsonResponse);
|
||||
var sutProvider = GetSutProvider(syncJsonResponse);
|
||||
billingSyncConnection.SetConfig(new BillingSyncConfig
|
||||
{
|
||||
BillingSyncKey = "okslkcslkjf"
|
||||
|
Reference in New Issue
Block a user