using System.Security.Claims; using System.Text; using Bit.Core.AdminConsole.Entities; using Bit.Core.Billing.Enums; using Bit.Core.Billing.Licenses.Attributes; using Bit.Core.Billing.Licenses.Extensions; using Bit.Core.Enums; using Bit.Core.Services; using Bit.Core.Settings; namespace Bit.Core.Models.Business; public class OrganizationLicense : BaseLicense { public OrganizationLicense() { } /// /// Initializes a new instance of the class. /// /// /// /// ⚠️ DEPRECATED: This constructor and the entire property-based licensing system is deprecated. /// Do not add new properties to this constructor or extend its functionality. /// /// /// This implementation has been replaced by a new claims-based licensing system that provides better security /// and flexibility. The new system uses JWT claims to store and validate license information, making it more /// secure and easier to extend without requiring changes to the license format. /// /// /// For new license-related features or modifications: /// 1. Use the claims-based system instead of adding properties here /// 2. Add new claims to the license token /// 3. Validate claims in the and methods /// /// /// This constructor is maintained only for backward compatibility with existing licenses. /// /// /// The organization to create the license for. /// Information about the organization's subscription. /// The ID of the current installation. /// The service used to sign the license. /// Optional version number for the license format. public OrganizationLicense(Organization org, SubscriptionInfo subscriptionInfo, Guid installationId, ILicensingService licenseService, int? version = null) { Version = version.GetValueOrDefault(CurrentLicenseFileVersion); // TODO: Remember to change the constant LicenseType = Enums.LicenseType.Organization; LicenseKey = org.LicenseKey; InstallationId = installationId; Id = org.Id; Name = org.Name; BillingEmail = org.BillingEmail; BusinessName = org.BusinessName; Enabled = org.Enabled; Plan = org.Plan; PlanType = org.PlanType; Seats = org.Seats; MaxCollections = org.MaxCollections; UsePolicies = org.UsePolicies; UseSso = org.UseSso; UseKeyConnector = org.UseKeyConnector; UseScim = org.UseScim; UseGroups = org.UseGroups; UseEvents = org.UseEvents; UseDirectory = org.UseDirectory; UseTotp = org.UseTotp; Use2fa = org.Use2fa; UseApi = org.UseApi; UseResetPassword = org.UseResetPassword; MaxStorageGb = org.MaxStorageGb; SelfHost = org.SelfHost; UsersGetPremium = org.UsersGetPremium; UseCustomPermissions = org.UseCustomPermissions; Issued = DateTime.UtcNow; UsePasswordManager = org.UsePasswordManager; UseSecretsManager = org.UseSecretsManager; SmSeats = org.SmSeats; SmServiceAccounts = org.SmServiceAccounts; UseRiskInsights = org.UseRiskInsights; UseOrganizationDomains = org.UseOrganizationDomains; // Deprecated. Left for backwards compatibility with old license versions. LimitCollectionCreationDeletion = org.LimitCollectionCreation || org.LimitCollectionDeletion; AllowAdminAccessToAllCollectionItems = org.AllowAdminAccessToAllCollectionItems; // Expires = org.CalculateFreshExpirationDate(subscriptionInfo, Issued); Refresh = org.CalculateFreshRefreshDate(subscriptionInfo, Expires, Issued); ExpirationWithoutGracePeriod = org.CalculateFreshExpirationDateWithoutGracePeriod(subscriptionInfo); Trial = org.IsTrialing(subscriptionInfo); UseAdminSponsoredFamilies = org.UseAdminSponsoredFamilies; Hash = Convert.ToBase64String(this.ComputeHash()); Signature = Convert.ToBase64String(licenseService.SignLicense(this)); } /// /// Represents the current version of the license format. Should be updated whenever new fields are added. /// /// Intentionally set one version behind to allow self hosted users some time to update before /// getting out of date license errors /// public const int CurrentLicenseFileVersion = 15; [LicenseVersion(1)] public Guid InstallationId { get; set; } [LicenseVersion(1)] public int? Seats { get; set; } [LicenseVersion(1)] public short? MaxCollections { get; set; } [LicenseVersion(1)] public short? MaxStorageGb { get; set; } [LicenseVersion(1)] public bool Enabled { get; set; } [LicenseVersion(1)] public bool SelfHost { get; set; } [LicenseVersion(1)] public bool UseDirectory { get; set; } [LicenseVersion(1)] public bool UseGroups { get; set; } [LicenseVersion(1)] public bool UseTotp { get; set; } [LicenseVersion(1)] public string BillingEmail { get; set; } [LicenseVersion(1)] public string BusinessName { get; set; } [LicenseVersion(1)] public string Plan { get; set; } [LicenseVersion(1)] public PlanType PlanType { get; set; } [LicenseVersion(2)] public bool UsersGetPremium { get; set; } [LicenseVersion(3)] public bool UseEvents { get; set; } [LicenseVersion(4)] public bool Use2fa { get; set; } [LicenseVersion(5)] public bool UseApi { get; set; } [LicenseVersion(6)] public bool UsePolicies { get; set; } [LicenseVersion(7)] public bool UseSso { get; set; } [LicenseVersion(8)] public bool UseResetPassword { get; set; } [LicenseVersion(9)] public bool UseKeyConnector { get; set; } [LicenseVersion(10)] public bool UseScim { get; set; } [LicenseVersion(11)] public bool UseCustomPermissions { get; set; } [LicenseVersion(12)] public DateTime? ExpirationWithoutGracePeriod { get; set; } [LicenseVersion(13)] public bool UsePasswordManager { get; set; } [LicenseVersion(13)] public bool UseSecretsManager { get; set; } [LicenseVersion(13)] public int? SmSeats { get; set; } [LicenseVersion(13)] public int? SmServiceAccounts { get; set; } // Deprecated. Left for backwards compatibility with old license versions. [LicenseVersion(14)] public bool LimitCollectionCreationDeletion { get; set; } = true; [LicenseVersion(15)] public bool AllowAdminAccessToAllCollectionItems { get; set; } = true; // [LicenseVersion(16)] public bool UseOrganizationDomains { get; set; } [LicenseIgnore] public bool UseAdminSponsoredFamilies { get; set; } [LicenseIgnore] public bool UseRiskInsights { get; set; } private bool ValidLicenseVersion { get => Version is >= 1 and <= CurrentLicenseFileVersion + 1; } public override byte[] GetDataBytes(bool forHash = false) { if (!ValidLicenseVersion) { throw new NotSupportedException($"Version {Version} is not supported."); } return this.GetDataBytesWithAttributes(forHash); } public bool CanUse( IGlobalSettings globalSettings, ClaimsPrincipal claimsPrincipal, out string exception) { var errorMessages = new StringBuilder(); var enabled = claimsPrincipal.GetValue(nameof(Enabled)); if (!enabled) { errorMessages.AppendLine("Your cloud-hosted organization is currently disabled."); } var installationId = claimsPrincipal.GetValue(nameof(InstallationId)); if (installationId != globalSettings.Installation.Id) { errorMessages.AppendLine("The installation ID does not match the current installation."); } var selfHost = claimsPrincipal.GetValue(nameof(SelfHost)); if (!selfHost) { errorMessages.AppendLine("The license does not allow for on-premise hosting of organizations."); } var licenseType = claimsPrincipal.GetValue(nameof(LicenseType)); if (licenseType != LicenseType.Organization) { errorMessages.AppendLine("Premium licenses cannot be applied to an organization. " + "Upload this license from your personal account settings page."); } if (errorMessages.Length > 0) { exception = $"Invalid license. {errorMessages.ToString().TrimEnd()}"; return false; } exception = ""; return true; } public bool VerifyData( Organization organization, ClaimsPrincipal claimsPrincipal, IGlobalSettings globalSettings) { var issued = claimsPrincipal.GetValue(nameof(Issued)); var expires = claimsPrincipal.GetValue(nameof(Expires)); var installationId = claimsPrincipal.GetValue(nameof(InstallationId)); var licenseKey = claimsPrincipal.GetValue(nameof(LicenseKey)); var enabled = claimsPrincipal.GetValue(nameof(Enabled)); var planType = claimsPrincipal.GetValue(nameof(PlanType)); var seats = claimsPrincipal.GetValue(nameof(Seats)); var maxCollections = claimsPrincipal.GetValue(nameof(MaxCollections)); var useGroups = claimsPrincipal.GetValue(nameof(UseGroups)); var useDirectory = claimsPrincipal.GetValue(nameof(UseDirectory)); var useTotp = claimsPrincipal.GetValue(nameof(UseTotp)); var selfHost = claimsPrincipal.GetValue(nameof(SelfHost)); var name = claimsPrincipal.GetValue(nameof(Name)); var usersGetPremium = claimsPrincipal.GetValue(nameof(UsersGetPremium)); var useEvents = claimsPrincipal.GetValue(nameof(UseEvents)); var use2fa = claimsPrincipal.GetValue(nameof(Use2fa)); var useApi = claimsPrincipal.GetValue(nameof(UseApi)); var usePolicies = claimsPrincipal.GetValue(nameof(UsePolicies)); var useSso = claimsPrincipal.GetValue(nameof(UseSso)); var useResetPassword = claimsPrincipal.GetValue(nameof(UseResetPassword)); var useKeyConnector = claimsPrincipal.GetValue(nameof(UseKeyConnector)); var useScim = claimsPrincipal.GetValue(nameof(UseScim)); var useCustomPermissions = claimsPrincipal.GetValue(nameof(UseCustomPermissions)); var useSecretsManager = claimsPrincipal.GetValue(nameof(UseSecretsManager)); var usePasswordManager = claimsPrincipal.GetValue(nameof(UsePasswordManager)); var smSeats = claimsPrincipal.GetValue(nameof(SmSeats)); var smServiceAccounts = claimsPrincipal.GetValue(nameof(SmServiceAccounts)); var useAdminSponsoredFamilies = claimsPrincipal.GetValue(nameof(UseAdminSponsoredFamilies)); var useOrganizationDomains = claimsPrincipal.GetValue(nameof(UseOrganizationDomains)); return issued <= DateTime.UtcNow && expires >= DateTime.UtcNow && installationId == globalSettings.Installation.Id && licenseKey == organization.LicenseKey && enabled == organization.Enabled && planType == organization.PlanType && seats == organization.Seats && maxCollections == organization.MaxCollections && useGroups == organization.UseGroups && useDirectory == organization.UseDirectory && useTotp == organization.UseTotp && selfHost == organization.SelfHost && name == organization.Name && usersGetPremium == organization.UsersGetPremium && useEvents == organization.UseEvents && use2fa == organization.Use2fa && useApi == organization.UseApi && usePolicies == organization.UsePolicies && useSso == organization.UseSso && useResetPassword == organization.UseResetPassword && useKeyConnector == organization.UseKeyConnector && useScim == organization.UseScim && useCustomPermissions == organization.UseCustomPermissions && useSecretsManager == organization.UseSecretsManager && usePasswordManager == organization.UsePasswordManager && smSeats == organization.SmSeats && smServiceAccounts == organization.SmServiceAccounts && useAdminSponsoredFamilies == organization.UseAdminSponsoredFamilies && useOrganizationDomains == organization.UseOrganizationDomains; } }