1
0
mirror of https://github.com/bitwarden/server.git synced 2025-02-16 01:51:21 +01:00

verify and disable premium from license check

This commit is contained in:
Kyle Spearrin 2017-08-16 17:08:20 -04:00
parent cdc5310fc3
commit b14f6d080e
8 changed files with 54 additions and 34 deletions

View File

@ -18,17 +18,20 @@ namespace Bit.Core.IdentityServer
private readonly IUserService _userService;
private readonly IUserRepository _userRepository;
private readonly IOrganizationUserRepository _organizationUserRepository;
private readonly ILicensingService _licensingService;
private IdentityOptions _identityOptions;
public ProfileService(
IUserRepository userRepository,
IUserService userService,
IOrganizationUserRepository organizationUserRepository,
ILicensingService licensingService,
IOptions<IdentityOptions> identityOptionsAccessor)
{
_userRepository = userRepository;
_userService = userService;
_organizationUserRepository = organizationUserRepository;
_licensingService = licensingService;
_identityOptions = identityOptionsAccessor?.Value ?? new IdentityOptions();
}
@ -40,9 +43,10 @@ namespace Bit.Core.IdentityServer
var user = await _userService.GetUserByPrincipalAsync(context.Subject);
if(user != null)
{
var isPremium = await _licensingService.VerifyUserPremiumAsync(user);
newClaims.AddRange(new List<Claim>
{
new Claim("premium", user.Premium ? "true" : "false", ClaimValueTypes.Boolean),
new Claim("premium", isPremium ? "true" : "false", ClaimValueTypes.Boolean),
new Claim(JwtClaimTypes.Email, user.Email),
new Claim(JwtClaimTypes.EmailVerified, user.EmailVerified ? "true" : "false", ClaimValueTypes.Boolean),
new Claim(_identityOptions.ClaimsIdentity.SecurityStampClaimType, user.SecurityStamp)

View File

@ -167,7 +167,7 @@ namespace Bit.Core.Models.Business
if(Version == 1)
{
return
organization.LicenseKey.Equals(LicenseKey, StringComparison.InvariantCultureIgnoreCase) &&
organization.LicenseKey.Equals(LicenseKey) &&
organization.Enabled == Enabled &&
organization.PlanType == PlanType &&
organization.Seats == Seats &&

View File

@ -116,7 +116,7 @@ namespace Bit.Core.Models.Business
if(Version == 1)
{
return
user.LicenseKey.Equals(LicenseKey, StringComparison.InvariantCultureIgnoreCase) &&
user.LicenseKey.Equals(LicenseKey) &&
user.Premium == Premium &&
user.Email.Equals(Email, StringComparison.InvariantCultureIgnoreCase);
}

View File

@ -1,12 +1,13 @@
using Bit.Core.Models.Business;
using Bit.Core.Models.Table;
using System.Threading.Tasks;
namespace Bit.Core.Services
{
public interface ILicensingService
{
bool VerifyOrganizationPlan(Organization organization);
bool VerifyUserPremium(User user);
Task<bool> VerifyUserPremiumAsync(User user);
bool VerifyLicense(ILicense license);
byte[] SignLicense(ILicense license);
}

View File

@ -47,6 +47,7 @@ namespace Bit.Core.Services
Task CancelPremiumAsync(User user, bool endOfPeriod = false);
Task ReinstatePremiumAsync(User user);
Task DisablePremiumAsync(Guid userId, DateTime? expirationDate);
Task DisablePremiumAsync(User user, DateTime? expirationDate);
Task UpdatePremiumExpirationAsync(Guid userId, DateTime? expirationDate);
}
}

View File

@ -8,6 +8,7 @@ using System.Collections.Generic;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading.Tasks;
namespace Bit.Core.Services
{
@ -15,13 +16,17 @@ namespace Bit.Core.Services
{
private readonly X509Certificate2 _certificate;
private readonly GlobalSettings _globalSettings;
private IDictionary<string, UserLicense> _userLicenseCache;
private IDictionary<string, OrganizationLicense> _organizationLicenseCache;
private IDictionary<Guid, DateTime> _userCheckCache = new Dictionary<Guid, DateTime>();
private IDictionary<Guid, DateTime> _organizationCheckCache = new Dictionary<Guid, DateTime>();
private readonly IUserService _userService;
public RsaLicensingService(
IUserService userService,
IHostingEnvironment environment,
GlobalSettings globalSettings)
{
_userService = userService;
var certThumbprint = "207e64a231e8aa32aaf68a61037c075ebebd553f";
_globalSettings = globalSettings;
_certificate = !_globalSettings.SelfHosted ? CoreHelpers.GetCertificate(certThumbprint)
@ -54,7 +59,7 @@ namespace Bit.Core.Services
return license != null && license.VerifyData(organization) && license.VerifySignature(_certificate);
}
public bool VerifyUserPremium(User user)
public async Task<bool> VerifyUserPremiumAsync(User user)
{
if(!_globalSettings.SelfHosted)
{
@ -66,8 +71,33 @@ namespace Bit.Core.Services
return false;
}
// Only check once per day
var now = DateTime.UtcNow;
if(_userCheckCache.ContainsKey(user.Id))
{
var lastCheck = _userCheckCache[user.Id];
if(lastCheck < now && now - lastCheck < TimeSpan.FromDays(1))
{
return user.Premium;
}
else
{
_userCheckCache[user.Id] = now;
}
}
else
{
_userCheckCache.Add(user.Id, now);
}
var license = ReadUserLicense(user);
return license != null && license.VerifyData(user) && license.VerifySignature(_certificate);
var licensedForPremium = license != null && license.VerifyData(user) && license.VerifySignature(_certificate);
if(!licensedForPremium)
{
await _userService.DisablePremiumAsync(user, license.Expires);
}
return licensedForPremium;
}
public bool VerifyLicense(ILicense license)
@ -87,11 +117,6 @@ namespace Bit.Core.Services
private UserLicense ReadUserLicense(User user)
{
if(_userLicenseCache != null && _userLicenseCache.ContainsKey(user.LicenseKey))
{
return _userLicenseCache[user.LicenseKey];
}
var filePath = $"{_globalSettings.LicenseDirectory}/user/{user.Id}.json";
if(!File.Exists(filePath))
{
@ -99,22 +124,11 @@ namespace Bit.Core.Services
}
var data = File.ReadAllText(filePath, Encoding.UTF8);
var obj = JsonConvert.DeserializeObject<UserLicense>(data);
if(_userLicenseCache == null)
{
_userLicenseCache = new Dictionary<string, UserLicense>();
}
_userLicenseCache.Add(obj.LicenseKey, obj);
return obj;
return JsonConvert.DeserializeObject<UserLicense>(data);
}
private OrganizationLicense ReadOrganiztionLicense(Organization organization)
{
if(_organizationLicenseCache != null && _organizationLicenseCache.ContainsKey(organization.LicenseKey))
{
return _organizationLicenseCache[organization.LicenseKey];
}
var filePath = $"{_globalSettings.LicenseDirectory}/organization/{organization.Id}.json";
if(!File.Exists(filePath))
{
@ -122,13 +136,7 @@ namespace Bit.Core.Services
}
var data = File.ReadAllText(filePath, Encoding.UTF8);
var obj = JsonConvert.DeserializeObject<OrganizationLicense>(data);
if(_organizationLicenseCache == null)
{
_organizationLicenseCache = new Dictionary<string, OrganizationLicense>();
}
_organizationLicenseCache.Add(obj.LicenseKey, obj);
return obj;
return JsonConvert.DeserializeObject<OrganizationLicense>(data);
}
}
}

View File

@ -691,6 +691,11 @@ namespace Bit.Core.Services
public async Task DisablePremiumAsync(Guid userId, DateTime? expirationDate)
{
var user = await _userRepository.GetByIdAsync(userId);
await DisablePremiumAsync(user, expirationDate);
}
public async Task DisablePremiumAsync(User user, DateTime? expirationDate)
{
if(user != null && user.Premium)
{
user.Premium = false;

View File

@ -2,6 +2,7 @@
using Microsoft.AspNetCore.Hosting;
using System;
using Bit.Core.Models.Business;
using System.Threading.Tasks;
namespace Bit.Core.Services
{
@ -27,9 +28,9 @@ namespace Bit.Core.Services
return true;
}
public bool VerifyUserPremium(User user)
public Task<bool> VerifyUserPremiumAsync(User user)
{
return user.Premium;
return Task.FromResult(user.Premium);
}
public byte[] SignLicense(ILicense license)