mirror of
https://github.com/bitwarden/server.git
synced 2025-02-16 01:51:21 +01:00
[AC-358] Server changes for self host subscription page changes (#2826)
* [AC-358] Add constant for grace period length * [AC-358] Add SubscriptionExpiration to OrganizationLicense.cs and increment Current_License_File_Version * [AC-358] Update org subscription response model - Add new SelfHostSubscriptionExpiration field that does not include a grace period - Add optional License argument to constructor for self host responses - Use the License, if available, to populate the expiration/subscription expiration fields - Maintain backwards compatability by falling back to organization expiration date * [AC-358] Read organization license file for self hosted subscription response * [AC-358] Decrement current license file version and add comment documenting why * [AC-358] Clarify name for new expiration without grace period field
This commit is contained in:
parent
8d3fe12170
commit
bfd3f85bb0
@ -50,6 +50,7 @@ public class OrganizationsController : Controller
|
|||||||
private readonly ICloudGetOrganizationLicenseQuery _cloudGetOrganizationLicenseQuery;
|
private readonly ICloudGetOrganizationLicenseQuery _cloudGetOrganizationLicenseQuery;
|
||||||
private readonly IFeatureService _featureService;
|
private readonly IFeatureService _featureService;
|
||||||
private readonly GlobalSettings _globalSettings;
|
private readonly GlobalSettings _globalSettings;
|
||||||
|
private readonly ILicensingService _licensingService;
|
||||||
|
|
||||||
public OrganizationsController(
|
public OrganizationsController(
|
||||||
IOrganizationRepository organizationRepository,
|
IOrganizationRepository organizationRepository,
|
||||||
@ -69,7 +70,8 @@ public class OrganizationsController : Controller
|
|||||||
IUpdateOrganizationLicenseCommand updateOrganizationLicenseCommand,
|
IUpdateOrganizationLicenseCommand updateOrganizationLicenseCommand,
|
||||||
ICloudGetOrganizationLicenseQuery cloudGetOrganizationLicenseQuery,
|
ICloudGetOrganizationLicenseQuery cloudGetOrganizationLicenseQuery,
|
||||||
IFeatureService featureService,
|
IFeatureService featureService,
|
||||||
GlobalSettings globalSettings)
|
GlobalSettings globalSettings,
|
||||||
|
ILicensingService licensingService)
|
||||||
{
|
{
|
||||||
_organizationRepository = organizationRepository;
|
_organizationRepository = organizationRepository;
|
||||||
_organizationUserRepository = organizationUserRepository;
|
_organizationUserRepository = organizationUserRepository;
|
||||||
@ -89,6 +91,7 @@ public class OrganizationsController : Controller
|
|||||||
_cloudGetOrganizationLicenseQuery = cloudGetOrganizationLicenseQuery;
|
_cloudGetOrganizationLicenseQuery = cloudGetOrganizationLicenseQuery;
|
||||||
_featureService = featureService;
|
_featureService = featureService;
|
||||||
_globalSettings = globalSettings;
|
_globalSettings = globalSettings;
|
||||||
|
_licensingService = licensingService;
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{id}")]
|
[HttpGet("{id}")]
|
||||||
@ -156,10 +159,14 @@ public class OrganizationsController : Controller
|
|||||||
|
|
||||||
return new OrganizationSubscriptionResponseModel(organization, subscriptionInfo, hideSensitiveData);
|
return new OrganizationSubscriptionResponseModel(organization, subscriptionInfo, hideSensitiveData);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (_globalSettings.SelfHosted)
|
||||||
{
|
{
|
||||||
return new OrganizationSubscriptionResponseModel(organization);
|
var orgLicense = await _licensingService.ReadOrganizationLicenseAsync(organization);
|
||||||
|
return new OrganizationSubscriptionResponseModel(organization, orgLicense);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return new OrganizationSubscriptionResponseModel(organization);
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{id}/license")]
|
[HttpGet("{id}/license")]
|
||||||
|
@ -3,6 +3,7 @@ using Bit.Core.Enums;
|
|||||||
using Bit.Core.Models.Api;
|
using Bit.Core.Models.Api;
|
||||||
using Bit.Core.Models.Business;
|
using Bit.Core.Models.Business;
|
||||||
using Bit.Core.Utilities;
|
using Bit.Core.Utilities;
|
||||||
|
using Constants = Bit.Core.Constants;
|
||||||
|
|
||||||
namespace Bit.Api.Models.Response.Organizations;
|
namespace Bit.Api.Models.Response.Organizations;
|
||||||
|
|
||||||
@ -108,9 +109,32 @@ public class OrganizationSubscriptionResponseModel : OrganizationResponseModel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OrganizationSubscriptionResponseModel(Organization organization, OrganizationLicense license) :
|
||||||
|
this(organization)
|
||||||
|
{
|
||||||
|
if (license != null)
|
||||||
|
{
|
||||||
|
// License expiration should always include grace period - See OrganizationLicense.cs
|
||||||
|
Expiration = license.Expires;
|
||||||
|
// Use license.ExpirationWithoutGracePeriod if available, otherwise assume license expiration minus grace period
|
||||||
|
ExpirationWithoutGracePeriod = license.ExpirationWithoutGracePeriod ??
|
||||||
|
license.Expires?.AddDays(-Constants
|
||||||
|
.OrganizationSelfHostSubscriptionGracePeriodDays);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public string StorageName { get; set; }
|
public string StorageName { get; set; }
|
||||||
public double? StorageGb { get; set; }
|
public double? StorageGb { get; set; }
|
||||||
public BillingSubscription Subscription { get; set; }
|
public BillingSubscription Subscription { get; set; }
|
||||||
public BillingSubscriptionUpcomingInvoice UpcomingInvoice { get; set; }
|
public BillingSubscriptionUpcomingInvoice UpcomingInvoice { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Date when a self-hosted organization's subscription expires, without any grace period.
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? ExpirationWithoutGracePeriod { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Date when a self-hosted organization expires (includes grace period).
|
||||||
|
/// </summary>
|
||||||
public DateTime? Expiration { get; set; }
|
public DateTime? Expiration { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,12 @@ public static class Constants
|
|||||||
public const long FileSize501mb = 501L * 1024L * 1024L;
|
public const long FileSize501mb = 501L * 1024L * 1024L;
|
||||||
public const string DatabaseFieldProtectorPurpose = "DatabaseFieldProtection";
|
public const string DatabaseFieldProtectorPurpose = "DatabaseFieldProtection";
|
||||||
public const string DatabaseFieldProtectedPrefix = "P|";
|
public const string DatabaseFieldProtectedPrefix = "P|";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Default number of days an organization has to apply an updated license to their self-hosted installation after
|
||||||
|
/// their subscription has expired.
|
||||||
|
/// </summary>
|
||||||
|
public const int OrganizationSelfHostSubscriptionGracePeriodDays = 60;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class TokenPurposes
|
public static class TokenPurposes
|
||||||
|
@ -78,7 +78,8 @@ public class OrganizationLicense : ILicense
|
|||||||
subscriptionInfo.Subscription.PeriodDuration > TimeSpan.FromDays(180))
|
subscriptionInfo.Subscription.PeriodDuration > TimeSpan.FromDays(180))
|
||||||
{
|
{
|
||||||
Refresh = DateTime.UtcNow.AddDays(30);
|
Refresh = DateTime.UtcNow.AddDays(30);
|
||||||
Expires = subscriptionInfo?.Subscription.PeriodEndDate.Value.AddDays(60);
|
Expires = subscriptionInfo.Subscription.PeriodEndDate?.AddDays(Constants.OrganizationSelfHostSubscriptionGracePeriodDays);
|
||||||
|
ExpirationWithoutGracePeriod = subscriptionInfo.Subscription.PeriodEndDate;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -123,6 +124,7 @@ public class OrganizationLicense : ILicense
|
|||||||
public DateTime Issued { get; set; }
|
public DateTime Issued { get; set; }
|
||||||
public DateTime? Refresh { get; set; }
|
public DateTime? Refresh { get; set; }
|
||||||
public DateTime? Expires { get; set; }
|
public DateTime? Expires { get; set; }
|
||||||
|
public DateTime? ExpirationWithoutGracePeriod { get; set; }
|
||||||
public bool Trial { get; set; }
|
public bool Trial { get; set; }
|
||||||
public LicenseType? LicenseType { get; set; }
|
public LicenseType? LicenseType { get; set; }
|
||||||
public string Hash { get; set; }
|
public string Hash { get; set; }
|
||||||
@ -133,10 +135,12 @@ public class OrganizationLicense : ILicense
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the current version of the license format. Should be updated whenever new fields are added.
|
/// Represents the current version of the license format. Should be updated whenever new fields are added.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private const int CURRENT_LICENSE_FILE_VERSION = 10;
|
/// <remarks>Intentionally set one version behind to allow self hosted users some time to update before
|
||||||
|
/// getting out of date license errors</remarks>
|
||||||
|
private const int CURRENT_LICENSE_FILE_VERSION = 11;
|
||||||
private bool ValidLicenseVersion
|
private bool ValidLicenseVersion
|
||||||
{
|
{
|
||||||
get => Version is >= 1 and <= 11;
|
get => Version is >= 1 and <= 12;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] GetDataBytes(bool forHash = false)
|
public byte[] GetDataBytes(bool forHash = false)
|
||||||
@ -170,6 +174,8 @@ public class OrganizationLicense : ILicense
|
|||||||
(Version >= 10 || !p.Name.Equals(nameof(UseScim))) &&
|
(Version >= 10 || !p.Name.Equals(nameof(UseScim))) &&
|
||||||
// UseCustomPermissions was added in Version 11
|
// UseCustomPermissions was added in Version 11
|
||||||
(Version >= 11 || !p.Name.Equals(nameof(UseCustomPermissions))) &&
|
(Version >= 11 || !p.Name.Equals(nameof(UseCustomPermissions))) &&
|
||||||
|
// ExpirationWithoutGracePeriod was added in Version 12
|
||||||
|
(Version >= 12 || !p.Name.Equals(nameof(ExpirationWithoutGracePeriod))) &&
|
||||||
(
|
(
|
||||||
!forHash ||
|
!forHash ||
|
||||||
(
|
(
|
||||||
|
@ -40,6 +40,7 @@ public class OrganizationsControllerTests : IDisposable
|
|||||||
private readonly IUpdateOrganizationLicenseCommand _updateOrganizationLicenseCommand;
|
private readonly IUpdateOrganizationLicenseCommand _updateOrganizationLicenseCommand;
|
||||||
private readonly IOrganizationDomainRepository _organizationDomainRepository;
|
private readonly IOrganizationDomainRepository _organizationDomainRepository;
|
||||||
private readonly IFeatureService _featureService;
|
private readonly IFeatureService _featureService;
|
||||||
|
private readonly ILicensingService _licensingService;
|
||||||
|
|
||||||
private readonly OrganizationsController _sut;
|
private readonly OrganizationsController _sut;
|
||||||
|
|
||||||
@ -63,12 +64,13 @@ public class OrganizationsControllerTests : IDisposable
|
|||||||
_createOrganizationApiKeyCommand = Substitute.For<ICreateOrganizationApiKeyCommand>();
|
_createOrganizationApiKeyCommand = Substitute.For<ICreateOrganizationApiKeyCommand>();
|
||||||
_updateOrganizationLicenseCommand = Substitute.For<IUpdateOrganizationLicenseCommand>();
|
_updateOrganizationLicenseCommand = Substitute.For<IUpdateOrganizationLicenseCommand>();
|
||||||
_featureService = Substitute.For<IFeatureService>();
|
_featureService = Substitute.For<IFeatureService>();
|
||||||
|
_licensingService = Substitute.For<ILicensingService>();
|
||||||
|
|
||||||
_sut = new OrganizationsController(_organizationRepository, _organizationUserRepository,
|
_sut = new OrganizationsController(_organizationRepository, _organizationUserRepository,
|
||||||
_policyRepository, _providerRepository, _organizationService, _userService, _paymentService, _currentContext,
|
_policyRepository, _providerRepository, _organizationService, _userService, _paymentService, _currentContext,
|
||||||
_ssoConfigRepository, _ssoConfigService, _getOrganizationApiKeyQuery, _rotateOrganizationApiKeyCommand,
|
_ssoConfigRepository, _ssoConfigService, _getOrganizationApiKeyQuery, _rotateOrganizationApiKeyCommand,
|
||||||
_createOrganizationApiKeyCommand, _organizationApiKeyRepository, _updateOrganizationLicenseCommand,
|
_createOrganizationApiKeyCommand, _organizationApiKeyRepository, _updateOrganizationLicenseCommand,
|
||||||
_cloudGetOrganizationLicenseQuery, _featureService, _globalSettings);
|
_cloudGetOrganizationLicenseQuery, _featureService, _globalSettings, _licensingService);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
Loading…
Reference in New Issue
Block a user