mirror of
https://github.com/bitwarden/server.git
synced 2025-04-05 05:00:19 -05:00

* Added UseSso bool to org * Update fields in migration script * bump version & check enabled flag on ssoConfig
274 lines
10 KiB
C#
274 lines
10 KiB
C#
using Bit.Core.Enums;
|
|
using Bit.Core.Models.Table;
|
|
using Bit.Core.Services;
|
|
using Newtonsoft.Json;
|
|
using System;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Security.Cryptography;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
using System.Text;
|
|
|
|
namespace Bit.Core.Models.Business
|
|
{
|
|
public class OrganizationLicense : ILicense
|
|
{
|
|
public OrganizationLicense()
|
|
{ }
|
|
|
|
public OrganizationLicense(Organization org, SubscriptionInfo subscriptionInfo, Guid installationId,
|
|
ILicensingService licenseService)
|
|
{
|
|
Version = 6; // TODO: bump to version 7
|
|
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;
|
|
UseGroups = org.UseGroups;
|
|
UseEvents = org.UseEvents;
|
|
UseDirectory = org.UseDirectory;
|
|
UseTotp = org.UseTotp;
|
|
Use2fa = org.Use2fa;
|
|
UseApi = org.UseApi;
|
|
MaxStorageGb = org.MaxStorageGb;
|
|
SelfHost = org.SelfHost;
|
|
UsersGetPremium = org.UsersGetPremium;
|
|
Issued = DateTime.UtcNow;
|
|
|
|
if (subscriptionInfo?.Subscription == null)
|
|
{
|
|
if (org.PlanType == PlanType.Custom && org.ExpirationDate.HasValue)
|
|
{
|
|
Expires = Refresh = org.ExpirationDate.Value;
|
|
Trial = false;
|
|
}
|
|
else
|
|
{
|
|
Expires = Refresh = Issued.AddDays(7);
|
|
Trial = true;
|
|
}
|
|
}
|
|
else if (subscriptionInfo.Subscription.TrialEndDate.HasValue &&
|
|
subscriptionInfo.Subscription.TrialEndDate.Value > DateTime.UtcNow)
|
|
{
|
|
Expires = Refresh = subscriptionInfo.Subscription.TrialEndDate.Value;
|
|
Trial = true;
|
|
}
|
|
else
|
|
{
|
|
if (org.ExpirationDate.HasValue && org.ExpirationDate.Value < DateTime.UtcNow)
|
|
{
|
|
// expired
|
|
Expires = Refresh = org.ExpirationDate.Value;
|
|
}
|
|
else if (subscriptionInfo?.Subscription?.PeriodDuration != null &&
|
|
subscriptionInfo.Subscription.PeriodDuration > TimeSpan.FromDays(180))
|
|
{
|
|
Refresh = DateTime.UtcNow.AddDays(30);
|
|
Expires = subscriptionInfo?.Subscription.PeriodEndDate.Value.AddDays(60);
|
|
}
|
|
else
|
|
{
|
|
Expires = org.ExpirationDate.HasValue ? org.ExpirationDate.Value.AddMonths(11) : Issued.AddYears(1);
|
|
Refresh = DateTime.UtcNow - Expires > TimeSpan.FromDays(30) ? DateTime.UtcNow.AddDays(30) : Expires;
|
|
}
|
|
|
|
Trial = false;
|
|
}
|
|
|
|
Hash = Convert.ToBase64String(ComputeHash());
|
|
Signature = Convert.ToBase64String(licenseService.SignLicense(this));
|
|
}
|
|
|
|
public string LicenseKey { get; set; }
|
|
public Guid InstallationId { get; set; }
|
|
public Guid Id { get; set; }
|
|
public string Name { get; set; }
|
|
public string BillingEmail { get; set; }
|
|
public string BusinessName { get; set; }
|
|
public bool Enabled { get; set; }
|
|
public string Plan { get; set; }
|
|
public PlanType PlanType { get; set; }
|
|
public short? Seats { get; set; }
|
|
public short? MaxCollections { get; set; }
|
|
public bool UsePolicies { get; set; }
|
|
public bool UseSso { get; set; }
|
|
public bool UseGroups { get; set; }
|
|
public bool UseEvents { get; set; }
|
|
public bool UseDirectory { get; set; }
|
|
public bool UseTotp { get; set; }
|
|
public bool Use2fa { get; set; }
|
|
public bool UseApi { get; set; }
|
|
public short? MaxStorageGb { get; set; }
|
|
public bool SelfHost { get; set; }
|
|
public bool UsersGetPremium { get; set; }
|
|
public int Version { get; set; }
|
|
public DateTime Issued { get; set; }
|
|
public DateTime? Refresh { get; set; }
|
|
public DateTime? Expires { get; set; }
|
|
public bool Trial { get; set; }
|
|
public string Hash { get; set; }
|
|
public string Signature { get; set; }
|
|
[JsonIgnore]
|
|
public byte[] SignatureBytes => Convert.FromBase64String(Signature);
|
|
|
|
public byte[] GetDataBytes(bool forHash = false)
|
|
{
|
|
string data = null;
|
|
if (Version >= 1 && Version <= 7)
|
|
{
|
|
var props = typeof(OrganizationLicense)
|
|
.GetProperties(BindingFlags.Public | BindingFlags.Instance)
|
|
.Where(p =>
|
|
!p.Name.Equals(nameof(Signature)) &&
|
|
!p.Name.Equals(nameof(SignatureBytes)) &&
|
|
// UsersGetPremium was added in Version 2
|
|
(Version >= 2 || !p.Name.Equals(nameof(UsersGetPremium))) &&
|
|
// UseEvents was added in Version 3
|
|
(Version >= 3 || !p.Name.Equals(nameof(UseEvents))) &&
|
|
// Use2fa was added in Version 4
|
|
(Version >= 4 || !p.Name.Equals(nameof(Use2fa))) &&
|
|
// UseApi was added in Version 5
|
|
(Version >= 5 || !p.Name.Equals(nameof(UseApi))) &&
|
|
// UsePolicies was added in Version 6
|
|
(Version >= 6 || !p.Name.Equals(nameof(UsePolicies))) &&
|
|
// UseSso was added in Version 7
|
|
(Version >= 7 || !p.Name.Equals(nameof(UseSso))) &&
|
|
(
|
|
!forHash ||
|
|
(
|
|
!p.Name.Equals(nameof(Hash)) &&
|
|
!p.Name.Equals(nameof(Issued)) &&
|
|
!p.Name.Equals(nameof(Refresh))
|
|
)
|
|
))
|
|
.OrderBy(p => p.Name)
|
|
.Select(p => $"{p.Name}:{Utilities.CoreHelpers.FormatLicenseSignatureValue(p.GetValue(this, null))}")
|
|
.Aggregate((c, n) => $"{c}|{n}");
|
|
data = $"license:organization|{props}";
|
|
}
|
|
else
|
|
{
|
|
throw new NotSupportedException($"Version {Version} is not supported.");
|
|
}
|
|
|
|
return Encoding.UTF8.GetBytes(data);
|
|
}
|
|
|
|
public byte[] ComputeHash()
|
|
{
|
|
using (var alg = SHA256.Create())
|
|
{
|
|
return alg.ComputeHash(GetDataBytes(true));
|
|
}
|
|
}
|
|
|
|
public bool CanUse(GlobalSettings globalSettings)
|
|
{
|
|
if (!Enabled || Issued > DateTime.UtcNow || Expires < DateTime.UtcNow)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (Version >= 1 && Version <= 7)
|
|
{
|
|
return InstallationId == globalSettings.Installation.Id && SelfHost;
|
|
}
|
|
else
|
|
{
|
|
throw new NotSupportedException($"Version {Version} is not supported.");
|
|
}
|
|
}
|
|
|
|
public bool VerifyData(Organization organization, GlobalSettings globalSettings)
|
|
{
|
|
if (Issued > DateTime.UtcNow || Expires < DateTime.UtcNow)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (Version >= 1 && Version <= 7)
|
|
{
|
|
var valid =
|
|
globalSettings.Installation.Id == InstallationId &&
|
|
organization.LicenseKey != null && organization.LicenseKey.Equals(LicenseKey) &&
|
|
organization.Enabled == Enabled &&
|
|
organization.PlanType == PlanType &&
|
|
organization.Seats == Seats &&
|
|
organization.MaxCollections == MaxCollections &&
|
|
organization.UseGroups == UseGroups &&
|
|
organization.UseDirectory == UseDirectory &&
|
|
organization.UseTotp == UseTotp &&
|
|
organization.SelfHost == SelfHost &&
|
|
organization.Name.Equals(Name);
|
|
|
|
if (valid && Version >= 2)
|
|
{
|
|
valid = organization.UsersGetPremium == UsersGetPremium;
|
|
}
|
|
|
|
if (valid && Version >= 3)
|
|
{
|
|
valid = organization.UseEvents == UseEvents;
|
|
}
|
|
|
|
if (valid && Version >= 4)
|
|
{
|
|
valid = organization.Use2fa == Use2fa;
|
|
}
|
|
|
|
if (valid && Version >= 5)
|
|
{
|
|
valid = organization.UseApi == UseApi;
|
|
}
|
|
|
|
if (valid && Version >= 6)
|
|
{
|
|
valid = organization.UsePolicies == UsePolicies;
|
|
}
|
|
|
|
if (valid && Version >= 7)
|
|
{
|
|
valid = organization.UseSso == UseSso;
|
|
}
|
|
|
|
return valid;
|
|
}
|
|
else
|
|
{
|
|
throw new NotSupportedException($"Version {Version} is not supported.");
|
|
}
|
|
}
|
|
|
|
public bool VerifySignature(X509Certificate2 certificate)
|
|
{
|
|
using (var rsa = certificate.GetRSAPublicKey())
|
|
{
|
|
return rsa.VerifyData(GetDataBytes(), SignatureBytes, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
|
}
|
|
}
|
|
|
|
public byte[] Sign(X509Certificate2 certificate)
|
|
{
|
|
if (!certificate.HasPrivateKey)
|
|
{
|
|
throw new InvalidOperationException("You don't have the private key!");
|
|
}
|
|
|
|
using (var rsa = certificate.GetRSAPrivateKey())
|
|
{
|
|
return rsa.SignData(GetDataBytes(), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
|
}
|
|
}
|
|
}
|
|
}
|