1
0
mirror of https://github.com/bitwarden/server.git synced 2025-02-09 00:41:37 +01:00

validate organization licenses

This commit is contained in:
Kyle Spearrin 2017-08-17 00:12:11 -04:00
parent 127ff2d361
commit 4585af5a85
9 changed files with 64 additions and 19 deletions

View File

@ -37,13 +37,15 @@ namespace Bit.Core.IdentityServer
public async Task GetProfileDataAsync(ProfileDataRequestContext context) public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{ {
await _licensingService.ValidateOrganizationsAsync();
var existingClaims = context.Subject.Claims; var existingClaims = context.Subject.Claims;
var newClaims = new List<Claim>(); var newClaims = new List<Claim>();
var user = await _userService.GetUserByPrincipalAsync(context.Subject); var user = await _userService.GetUserByPrincipalAsync(context.Subject);
if(user != null) if(user != null)
{ {
var isPremium = await _licensingService.VerifyUserPremiumAsync(user); var isPremium = await _licensingService.ValidateUserPremiumAsync(user);
newClaims.AddRange(new List<Claim> newClaims.AddRange(new List<Claim>
{ {
new Claim("premium", isPremium ? "true" : "false", ClaimValueTypes.Boolean), new Claim("premium", isPremium ? "true" : "false", ClaimValueTypes.Boolean),

View File

@ -140,7 +140,7 @@ namespace Bit.Core.Models.Business
} }
} }
public bool CanUse(Guid installationId) public bool CanUse(GlobalSettings globalSettings)
{ {
if(!Enabled || Issued > DateTime.UtcNow || Expires < DateTime.UtcNow) if(!Enabled || Issued > DateTime.UtcNow || Expires < DateTime.UtcNow)
{ {
@ -149,7 +149,7 @@ namespace Bit.Core.Models.Business
if(Version == 1) if(Version == 1)
{ {
return InstallationId == installationId && SelfHost; return InstallationId == globalSettings.Installation.Id && SelfHost;
} }
else else
{ {
@ -157,7 +157,7 @@ namespace Bit.Core.Models.Business
} }
} }
public bool VerifyData(Organization organization) public bool VerifyData(Organization organization, GlobalSettings globalSettings)
{ {
if(Issued > DateTime.UtcNow || Expires < DateTime.UtcNow) if(Issued > DateTime.UtcNow || Expires < DateTime.UtcNow)
{ {
@ -167,6 +167,7 @@ namespace Bit.Core.Models.Business
if(Version == 1) if(Version == 1)
{ {
return return
globalSettings.Installation.Id == InstallationId &&
organization.LicenseKey.Equals(LicenseKey) && organization.LicenseKey.Equals(LicenseKey) &&
organization.Enabled == Enabled && organization.Enabled == Enabled &&
organization.PlanType == PlanType && organization.PlanType == PlanType &&
@ -175,7 +176,8 @@ namespace Bit.Core.Models.Business
organization.UseGroups == UseGroups && organization.UseGroups == UseGroups &&
organization.UseDirectory == UseDirectory && organization.UseDirectory == UseDirectory &&
organization.UseTotp == UseTotp && organization.UseTotp == UseTotp &&
organization.SelfHost == SelfHost; organization.SelfHost == SelfHost &&
organization.Name.Equals(Name);
} }
else else
{ {

View File

@ -7,6 +7,7 @@ namespace Bit.Core.Repositories
{ {
public interface IOrganizationRepository : IRepository<Organization, Guid> public interface IOrganizationRepository : IRepository<Organization, Guid>
{ {
Task<ICollection<Organization>> GetManyAsync();
Task<ICollection<Organization>> GetManyByUserIdAsync(Guid userId); Task<ICollection<Organization>> GetManyByUserIdAsync(Guid userId);
Task UpdateStorageAsync(Guid id); Task UpdateStorageAsync(Guid id);
} }

View File

@ -19,6 +19,18 @@ namespace Bit.Core.Repositories.SqlServer
: base(connectionString) : base(connectionString)
{ } { }
public async Task<ICollection<Organization>> GetManyAsync()
{
using(var connection = new SqlConnection(ConnectionString))
{
var results = await connection.QueryAsync<Organization>(
"[dbo].[Organization_Read]",
commandType: CommandType.StoredProcedure);
return results.ToList();
}
}
public async Task<ICollection<Organization>> GetManyByUserIdAsync(Guid userId) public async Task<ICollection<Organization>> GetManyByUserIdAsync(Guid userId)
{ {
using(var connection = new SqlConnection(ConnectionString)) using(var connection = new SqlConnection(ConnectionString))

View File

@ -6,8 +6,8 @@ namespace Bit.Core.Services
{ {
public interface ILicensingService public interface ILicensingService
{ {
bool VerifyOrganizationPlan(Organization organization); Task ValidateOrganizationsAsync();
Task<bool> VerifyUserPremiumAsync(User user); Task<bool> ValidateUserPremiumAsync(User user);
bool VerifyLicense(ILicense license); bool VerifyLicense(ILicense license);
byte[] SignLicense(ILicense license); byte[] SignLicense(ILicense license);
} }

View File

@ -548,7 +548,7 @@ namespace Bit.Core.Services
throw new BadRequestException("Invalid license."); throw new BadRequestException("Invalid license.");
} }
if(!license.CanUse(_globalSettings.Installation.Id)) if(!license.CanUse(_globalSettings))
{ {
throw new BadRequestException("Invalid license. Make sure your license allows for on-premise " + throw new BadRequestException("Invalid license. Make sure your license allows for on-premise " +
"hosting of organizations and that the installation id matches your current installation."); "hosting of organizations and that the installation id matches your current installation.");
@ -655,7 +655,7 @@ namespace Bit.Core.Services
throw new BadRequestException("Invalid license."); throw new BadRequestException("Invalid license.");
} }
if(!license.CanUse(_globalSettings.Installation.Id)) if(!license.CanUse(_globalSettings))
{ {
throw new BadRequestException("Invalid license. Make sure your license allows for on-premise " + throw new BadRequestException("Invalid license. Make sure your license allows for on-premise " +
"hosting of organizations and that the installation id matches your current installation."); "hosting of organizations and that the installation id matches your current installation.");

View File

@ -7,6 +7,7 @@ using Newtonsoft.Json;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -17,16 +18,20 @@ namespace Bit.Core.Services
{ {
private readonly X509Certificate2 _certificate; private readonly X509Certificate2 _certificate;
private readonly GlobalSettings _globalSettings; private readonly GlobalSettings _globalSettings;
private IDictionary<Guid, DateTime> _userCheckCache = new Dictionary<Guid, DateTime>();
private IDictionary<Guid, DateTime> _organizationCheckCache = new Dictionary<Guid, DateTime>();
private readonly IUserRepository _userRepository; private readonly IUserRepository _userRepository;
private readonly IOrganizationRepository _organizationRepository;
private IDictionary<Guid, DateTime> _userCheckCache = new Dictionary<Guid, DateTime>();
private DateTime? _organizationCheckCache = null;
public RsaLicensingService( public RsaLicensingService(
IUserRepository userRepository, IUserRepository userRepository,
IOrganizationRepository organizationRepository,
IHostingEnvironment environment, IHostingEnvironment environment,
GlobalSettings globalSettings) GlobalSettings globalSettings)
{ {
_userRepository = userRepository; _userRepository = userRepository;
_organizationRepository = organizationRepository;
var certThumbprint = "207e64a231e8aa32aaf68a61037c075ebebd553f"; var certThumbprint = "207e64a231e8aa32aaf68a61037c075ebebd553f";
_globalSettings = globalSettings; _globalSettings = globalSettings;
@ -44,23 +49,35 @@ namespace Bit.Core.Services
} }
} }
public bool VerifyOrganizationPlan(Organization organization) public async Task ValidateOrganizationsAsync()
{ {
if(!_globalSettings.SelfHosted) if(!_globalSettings.SelfHosted)
{ {
return true; return;
} }
if(!organization.SelfHost) var now = DateTime.UtcNow;
if(_organizationCheckCache.HasValue && now - _organizationCheckCache.Value < TimeSpan.FromDays(1))
{ {
return false; return;
} }
_organizationCheckCache = now;
var license = ReadOrganiztionLicense(organization); var orgs = await _organizationRepository.GetManyAsync();
return license != null && license.VerifyData(organization) && license.VerifySignature(_certificate); foreach(var org in orgs.Where(o => o.Enabled))
{
var license = ReadOrganiztionLicense(org);
if(license == null || !license.VerifyData(org, _globalSettings) || !license.VerifySignature(_certificate))
{
org.Enabled = false;
org.ExpirationDate = license.Expires;
org.RevisionDate = DateTime.UtcNow;
await _organizationRepository.ReplaceAsync(org);
}
}
} }
public async Task<bool> VerifyUserPremiumAsync(User user) public async Task<bool> ValidateUserPremiumAsync(User user)
{ {
if(!_globalSettings.SelfHosted) if(!_globalSettings.SelfHosted)
{ {

View File

@ -28,7 +28,7 @@ namespace Bit.Core.Services
return true; return true;
} }
public Task<bool> VerifyUserPremiumAsync(User user) public Task<bool> ValidateUserPremiumAsync(User user)
{ {
return Task.FromResult(user.Premium); return Task.FromResult(user.Premium);
} }

View File

@ -0,0 +1,11 @@
CREATE PROCEDURE [dbo].[Organization_Read]
@Id UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
SELECT
*
FROM
[dbo].[OrganizationView]
END