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

CanAccessPremium checks instead of User.Premium

This commit is contained in:
Kyle Spearrin 2018-08-28 16:23:58 -04:00
parent 90387cca0c
commit c41a1e0936
12 changed files with 130 additions and 35 deletions

View File

@ -342,9 +342,9 @@ namespace Bit.Api.Controllers
throw new BadRequestException("MasterPasswordHash", "Invalid password.");
}
if(premium && !user.Premium)
if(premium && !(await _userService.CanAccessPremium(user)))
{
throw new BadRequestException("Premium membership required.");
throw new BadRequestException("Premium status is required.");
}
return user;

View File

@ -4,19 +4,27 @@ using Microsoft.AspNetCore.Identity;
using Bit.Core.Models.Table;
using Bit.Core.Enums;
using OtpNet;
using Bit.Core.Services;
namespace Bit.Core.Identity
{
public class AuthenticatorTokenProvider : IUserTwoFactorTokenProvider<User>
{
public Task<bool> CanGenerateTwoFactorTokenAsync(UserManager<User> manager, User user)
private readonly IUserService _userService;
public AuthenticatorTokenProvider(IUserService userService)
{
_userService = userService;
}
public async Task<bool> CanGenerateTwoFactorTokenAsync(UserManager<User> manager, User user)
{
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.Authenticator);
var canGenerate = user.TwoFactorProviderIsEnabled(TwoFactorProviderType.Authenticator)
&& !string.IsNullOrWhiteSpace((string)provider.MetaData["Key"]);
return Task.FromResult(canGenerate);
if(string.IsNullOrWhiteSpace((string)provider.MetaData["Key"]))
{
return false;
}
return await user.TwoFactorProviderIsEnabledAsync(TwoFactorProviderType.Authenticator, _userService);
}
public Task<string> GenerateAsync(string purpose, UserManager<User> manager, User user)

View File

@ -4,28 +4,37 @@ using Bit.Core.Models.Table;
using Bit.Core.Enums;
using Bit.Core.Utilities.Duo;
using Bit.Core.Models;
using Bit.Core.Services;
namespace Bit.Core.Identity
{
public class DuoWebTokenProvider : IUserTwoFactorTokenProvider<User>
{
private readonly IUserService _userService;
private readonly GlobalSettings _globalSettings;
public DuoWebTokenProvider(GlobalSettings globalSettings)
public DuoWebTokenProvider(
IUserService userService,
GlobalSettings globalSettings)
{
_userService = userService;
_globalSettings = globalSettings;
}
public Task<bool> CanGenerateTwoFactorTokenAsync(UserManager<User> manager, User user)
public async Task<bool> CanGenerateTwoFactorTokenAsync(UserManager<User> manager, User user)
{
if(!user.Premium)
if(!(await _userService.CanAccessPremium(user)))
{
return Task.FromResult(false);
return false;
}
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.Duo);
var canGenerate = user.TwoFactorProviderIsEnabled(TwoFactorProviderType.Duo) && HasProperMetaData(provider);
return Task.FromResult(canGenerate);
if(!HasProperMetaData(provider))
{
return false;
}
return await user.TwoFactorProviderIsEnabledAsync(TwoFactorProviderType.Duo, _userService);
}
public Task<string> GenerateAsync(string purpose, UserManager<User> manager, User user)

View File

@ -11,32 +11,40 @@ using U2fLib = U2F.Core.Crypto.U2F;
using U2F.Core.Models;
using U2F.Core.Exceptions;
using System;
using Bit.Core.Services;
namespace Bit.Core.Identity
{
public class U2fTokenProvider : IUserTwoFactorTokenProvider<User>
{
private readonly IUserService _userService;
private readonly IU2fRepository _u2fRepository;
private readonly GlobalSettings _globalSettings;
public U2fTokenProvider(
IUserService userService,
IU2fRepository u2fRepository,
GlobalSettings globalSettings)
{
_userService = userService;
_u2fRepository = u2fRepository;
_globalSettings = globalSettings;
}
public Task<bool> CanGenerateTwoFactorTokenAsync(UserManager<User> manager, User user)
public async Task<bool> CanGenerateTwoFactorTokenAsync(UserManager<User> manager, User user)
{
if(!user.Premium)
if(!(await _userService.CanAccessPremium(user)))
{
return Task.FromResult(false);
return false;
}
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.U2f);
var canGenerate = user.TwoFactorProviderIsEnabled(TwoFactorProviderType.U2f) && HasProperMetaData(provider);
return Task.FromResult(canGenerate);
if(!HasProperMetaData(provider))
{
return false;
}
return await user.TwoFactorProviderIsEnabledAsync(TwoFactorProviderType.U2f, _userService);
}
public async Task<string> GenerateAsync(string purpose, UserManager<User> manager, User user)

View File

@ -4,30 +4,37 @@ using Bit.Core.Models.Table;
using Bit.Core.Enums;
using YubicoDotNetClient;
using System.Linq;
using Bit.Core.Services;
namespace Bit.Core.Identity
{
public class YubicoOtpTokenProvider : IUserTwoFactorTokenProvider<User>
{
private readonly IUserService _userService;
private readonly GlobalSettings _globalSettings;
public YubicoOtpTokenProvider(GlobalSettings globalSettings)
public YubicoOtpTokenProvider(
IUserService userService,
GlobalSettings globalSettings)
{
_userService = userService;
_globalSettings = globalSettings;
}
public Task<bool> CanGenerateTwoFactorTokenAsync(UserManager<User> manager, User user)
public async Task<bool> CanGenerateTwoFactorTokenAsync(UserManager<User> manager, User user)
{
if(!user.Premium)
if(!(await _userService.CanAccessPremium(user)))
{
return Task.FromResult(false);
return false;
}
var provider = user.GetTwoFactorProvider(TwoFactorProviderType.YubiKey);
var canGenerate = user.TwoFactorProviderIsEnabled(TwoFactorProviderType.YubiKey)
&& (provider?.MetaData.Values.Any(v => !string.IsNullOrWhiteSpace((string)v)) ?? false);
if(!provider?.MetaData.Values.Any(v => !string.IsNullOrWhiteSpace((string)v)) ?? true)
{
return false;
}
return Task.FromResult(canGenerate);
return await user.TwoFactorProviderIsEnabledAsync(TwoFactorProviderType.YubiKey, _userService);
}
public Task<string> GenerateAsync(string purpose, UserManager<User> manager, User user)

View File

@ -162,8 +162,13 @@ namespace Bit.Core.IdentityServer
if(user.GetTwoFactorProviders() != null)
{
enabledProviders.AddRange(
user.GetTwoFactorProviders().Where(p => user.TwoFactorProviderIsEnabled(p.Key)));
foreach(var p in user.GetTwoFactorProviders())
{
if(await user.TwoFactorProviderIsEnabledAsync(p.Key, _userService))
{
enabledProviders.Add(p);
}
}
}
if(!enabledProviders.Any())
@ -273,13 +278,14 @@ namespace Bit.Core.IdentityServer
case TwoFactorProviderType.YubiKey:
case TwoFactorProviderType.U2f:
case TwoFactorProviderType.Remember:
if(type != TwoFactorProviderType.Remember && !user.TwoFactorProviderIsEnabled(type))
if(type != TwoFactorProviderType.Remember &&
!(await user.TwoFactorProviderIsEnabledAsync(type, _userService)))
{
return false;
}
return await _userManager.VerifyTwoFactorTokenAsync(user, type.ToString(), token);
case TwoFactorProviderType.Email:
if(!user.TwoFactorProviderIsEnabled(type))
if(!(await user.TwoFactorProviderIsEnabledAsync(type, _userService)))
{
return false;
}
@ -305,7 +311,7 @@ namespace Bit.Core.IdentityServer
case TwoFactorProviderType.U2f:
case TwoFactorProviderType.Email:
case TwoFactorProviderType.YubiKey:
if(!user.TwoFactorProviderIsEnabled(type))
if(!(await user.TwoFactorProviderIsEnabledAsync(type, _userService)))
{
return null;
}

View File

@ -14,6 +14,7 @@ namespace Bit.Core.Models.Data
Use2fa = organization.Use2fa;
Using2fa = organization.Use2fa && organization.TwoFactorProviders != null &&
organization.TwoFactorProviders != "{}";
UsersGetPremium = organization.UsersGetPremium;
Enabled = organization.Enabled;
}
@ -21,6 +22,7 @@ namespace Bit.Core.Models.Data
public bool UseEvents { get; set; }
public bool Use2fa { get; set; }
public bool Using2fa { get; set; }
public bool UsersGetPremium { get; set; }
public bool Enabled { get; set; }
}
}

View File

@ -7,6 +7,7 @@ using System.Linq;
using Bit.Core.Services;
using Bit.Core.Exceptions;
using Microsoft.AspNetCore.Identity;
using System.Threading.Tasks;
namespace Bit.Core.Models.Table
{
@ -92,15 +93,21 @@ namespace Bit.Core.Models.Table
_twoFactorProviders = providers;
}
public bool TwoFactorProviderIsEnabled(TwoFactorProviderType provider)
public async Task<bool> TwoFactorProviderIsEnabledAsync(TwoFactorProviderType provider,
IUserService userService)
{
var providers = GetTwoFactorProviders();
if(providers == null || !providers.ContainsKey(provider))
if(providers == null || !providers.ContainsKey(provider) || !providers[provider].Enabled)
{
return false;
}
return providers[provider].Enabled && (Premium || !TwoFactorProvider.RequiresPremium(provider));
if(!TwoFactorProvider.RequiresPremium(provider))
{
return true;
}
return await userService.CanAccessPremium(this);
}
public bool TwoFactorIsEnabled()
@ -111,7 +118,7 @@ namespace Bit.Core.Models.Table
return false;
}
return providers.Any(p => (p.Value?.Enabled ?? false) &&
return providers.Any(p => (p.Value?.Enabled ?? false) &&
(Premium || !TwoFactorProvider.RequiresPremium(p.Key)));
}

View File

@ -53,5 +53,6 @@ namespace Bit.Core.Services
Task UpdatePremiumExpirationAsync(Guid userId, DateTime? expirationDate);
Task<UserLicense> GenerateLicenseAsync(User user, BillingInfo billingInfo = null);
Task<bool> CheckPasswordAsync(User user, string password);
Task<bool> CanAccessPremium(User user);
}
}

View File

@ -39,6 +39,7 @@ namespace Bit.Core.Services
private readonly IEnumerable<IPasswordValidator<User>> _passwordValidators;
private readonly ILicensingService _licenseService;
private readonly IEventService _eventService;
private readonly IApplicationCacheService _applicationCacheService;
private readonly IDataProtector _organizationServiceDataProtector;
private readonly CurrentContext _currentContext;
private readonly GlobalSettings _globalSettings;
@ -61,6 +62,7 @@ namespace Bit.Core.Services
ILogger<UserManager<User>> logger,
ILicensingService licenseService,
IEventService eventService,
IApplicationCacheService applicationCacheService,
IDataProtectionProvider dataProtectionProvider,
CurrentContext currentContext,
GlobalSettings globalSettings)
@ -87,6 +89,7 @@ namespace Bit.Core.Services
_passwordValidators = passwordValidators;
_licenseService = licenseService;
_eventService = eventService;
_applicationCacheService = applicationCacheService;
_organizationServiceDataProtector = dataProtectionProvider.CreateProtector(
"OrganizationServiceDataProtector");
_currentContext = currentContext;
@ -822,6 +825,22 @@ namespace Bit.Core.Services
return success;
}
public async Task<bool> CanAccessPremium(User user)
{
if(user.Premium)
{
return true;
}
if(!_currentContext?.Organizations?.Any() ?? true)
{
return false;
}
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
return _currentContext.Organizations.Any(o => orgAbilities.ContainsKey(o.Id) &&
orgAbilities[o.Id].UsersGetPremium);
}
private async Task<IdentityResult> UpdatePasswordHash(User user, string newPassword,
bool validatePassword = true, bool refreshStamp = true)
{

View File

@ -13,6 +13,7 @@ BEGIN
ELSE
0
END AS [Using2fa],
[UsersGetPremium],
[Enabled]
FROM
[dbo].[Organization]

View File

@ -0,0 +1,27 @@
IF OBJECT_ID('[dbo].[Organization_ReadAbilities]') IS NOT NULL
BEGIN
DROP PROCEDURE [dbo].[Organization_ReadAbilities]
END
GO
CREATE PROCEDURE [dbo].[Organization_ReadAbilities]
AS
BEGIN
SET NOCOUNT ON
SELECT
[Id],
[UseEvents],
[Use2fa],
CASE
WHEN [Use2fa] = 1 AND [TwoFactorProviders] IS NOT NULL AND [TwoFactorProviders] != '{}' THEN
1
ELSE
0
END AS [Using2fa],
[UsersGetPremium],
[Enabled]
FROM
[dbo].[Organization]
END
GO