diff --git a/src/Core/Identity/DuoTokenProvider.cs b/src/Core/Identity/DuoTokenProvider.cs index 40bb7f22db..aa68bc730d 100644 --- a/src/Core/Identity/DuoTokenProvider.cs +++ b/src/Core/Identity/DuoTokenProvider.cs @@ -12,6 +12,11 @@ namespace Bit.Core.Identity { public Task CanGenerateTwoFactorTokenAsync(UserManager manager, User user) { + if(!user.Premium) + { + return Task.FromResult(false); + } + var provider = user.GetTwoFactorProvider(TwoFactorProviderType.Duo); var canGenerate = user.TwoFactorProviderIsEnabled(TwoFactorProviderType.Duo) && !string.IsNullOrWhiteSpace((string)provider?.MetaData["UserId"]); @@ -22,6 +27,11 @@ namespace Bit.Core.Identity /// Ex: "auto", "push", "passcode:123456", "sms", "phone" public async Task GenerateAsync(string purpose, UserManager manager, User user) { + if(!user.Premium) + { + return Task.FromResult(null); + } + var provider = user.GetTwoFactorProvider(TwoFactorProviderType.Duo); var duoClient = new DuoApi((string)provider.MetaData["IKey"], (string)provider.MetaData["SKey"], (string)provider.MetaData["Host"]); @@ -61,6 +71,11 @@ namespace Bit.Core.Identity public async Task ValidateAsync(string purpose, string token, UserManager manager, User user) { + if(!user.Premium) + { + return false; + } + var provider = user.GetTwoFactorProvider(TwoFactorProviderType.Duo); var duoClient = new DuoApi((string)provider.MetaData["IKey"], (string)provider.MetaData["SKey"], (string)provider.MetaData["Host"]); diff --git a/src/Core/Identity/DuoWebTokenProvider.cs b/src/Core/Identity/DuoWebTokenProvider.cs index 2fcc298ea2..388326aef3 100644 --- a/src/Core/Identity/DuoWebTokenProvider.cs +++ b/src/Core/Identity/DuoWebTokenProvider.cs @@ -19,6 +19,11 @@ namespace Bit.Core.Identity public Task CanGenerateTwoFactorTokenAsync(UserManager manager, User user) { + if(!user.Premium) + { + return Task.FromResult(false); + } + var provider = user.GetTwoFactorProvider(TwoFactorProviderType.Duo); var canGenerate = user.TwoFactorProviderIsEnabled(TwoFactorProviderType.Duo) && HasProperMetaData(provider); return Task.FromResult(canGenerate); @@ -26,6 +31,11 @@ namespace Bit.Core.Identity public Task GenerateAsync(string purpose, UserManager manager, User user) { + if(!user.Premium) + { + return Task.FromResult(null); + } + var provider = user.GetTwoFactorProvider(TwoFactorProviderType.Duo); if(!HasProperMetaData(provider)) { @@ -39,6 +49,11 @@ namespace Bit.Core.Identity public Task ValidateAsync(string purpose, string token, UserManager manager, User user) { + if(!user.Premium) + { + return Task.FromResult(false); + } + var provider = user.GetTwoFactorProvider(TwoFactorProviderType.Duo); if(!HasProperMetaData(provider)) { diff --git a/src/Core/Identity/U2fTokenProvider.cs b/src/Core/Identity/U2fTokenProvider.cs index 1e72edb3ad..59bf3ce504 100644 --- a/src/Core/Identity/U2fTokenProvider.cs +++ b/src/Core/Identity/U2fTokenProvider.cs @@ -28,6 +28,11 @@ namespace Bit.Core.Identity public Task CanGenerateTwoFactorTokenAsync(UserManager manager, User user) { + if(!user.Premium) + { + return Task.FromResult(false); + } + var provider = user.GetTwoFactorProvider(TwoFactorProviderType.U2f); var canGenerate = user.TwoFactorProviderIsEnabled(TwoFactorProviderType.U2f) && HasProperMetaData(provider); return Task.FromResult(canGenerate); @@ -35,6 +40,11 @@ namespace Bit.Core.Identity public async Task GenerateAsync(string purpose, UserManager manager, User user) { + if(!user.Premium) + { + return null; + } + var provider = user.GetTwoFactorProvider(TwoFactorProviderType.U2f); if(!HasProperMetaData(provider)) { @@ -88,7 +98,7 @@ namespace Bit.Core.Identity public async Task ValidateAsync(string purpose, string token, UserManager manager, User user) { - if(string.IsNullOrWhiteSpace(token)) + if(!user.Premium || string.IsNullOrWhiteSpace(token)) { return false; } diff --git a/src/Core/Identity/YubicoOtpTokenProvider.cs b/src/Core/Identity/YubicoOtpTokenProvider.cs index 07779e1dff..319c1d905b 100644 --- a/src/Core/Identity/YubicoOtpTokenProvider.cs +++ b/src/Core/Identity/YubicoOtpTokenProvider.cs @@ -18,6 +18,11 @@ namespace Bit.Core.Identity public Task CanGenerateTwoFactorTokenAsync(UserManager manager, User user) { + if(!user.Premium) + { + return Task.FromResult(false); + } + var provider = user.GetTwoFactorProvider(TwoFactorProviderType.YubiKey); var canGenerate = user.TwoFactorProviderIsEnabled(TwoFactorProviderType.YubiKey) && (provider?.MetaData.Values.Any(v => !string.IsNullOrWhiteSpace((string)v)) ?? false); @@ -32,6 +37,11 @@ namespace Bit.Core.Identity public Task ValidateAsync(string purpose, string token, UserManager manager, User user) { + if(!user.Premium) + { + return Task.FromResult(false); + } + if(string.IsNullOrWhiteSpace(token) || token.Length != 44) { return Task.FromResult(false); diff --git a/src/Core/IdentityServer/ResourceOwnerPasswordValidator.cs b/src/Core/IdentityServer/ResourceOwnerPasswordValidator.cs index 9a9a0337fa..d62adc711f 100644 --- a/src/Core/IdentityServer/ResourceOwnerPasswordValidator.cs +++ b/src/Core/IdentityServer/ResourceOwnerPasswordValidator.cs @@ -122,7 +122,7 @@ namespace Bit.Core.IdentityServer { var providerKeys = new List(); var providers = new Dictionary>(); - var enabledProviders = user.GetTwoFactorProviders()?.Where(p => p.Value.Enabled); + var enabledProviders = user.GetTwoFactorProviders()?.Where(p => user.TwoFactorProviderIsEnabled(p.Key)); if(enabledProviders == null) { BuildErrorResult(false, context); @@ -192,6 +192,11 @@ namespace Bit.Core.IdentityServer private async Task VerifyTwoFactor(User user, TwoFactorProviderType type, string token) { + if(!user.TwoFactorProviderIsEnabled(type)) + { + return false; + } + switch(type) { case TwoFactorProviderType.Authenticator: @@ -210,6 +215,11 @@ namespace Bit.Core.IdentityServer private async Task> BuildTwoFactorParams(User user, TwoFactorProviderType type, TwoFactorProvider provider) { + if(!user.TwoFactorProviderIsEnabled(type)) + { + return null; + } + switch(type) { case TwoFactorProviderType.Duo: diff --git a/src/Core/Models/Table/User.cs b/src/Core/Models/Table/User.cs index 3b798ba732..4820f95192 100644 --- a/src/Core/Models/Table/User.cs +++ b/src/Core/Models/Table/User.cs @@ -90,7 +90,7 @@ namespace Bit.Core.Models.Table return false; } - return providers[provider].Enabled; + return providers[provider].Enabled && (Premium || !TwoFactorProvider.RequiresPremium(provider)); } public bool TwoFactorIsEnabled() @@ -101,7 +101,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))); } public TwoFactorProvider GetTwoFactorProvider(TwoFactorProviderType provider) diff --git a/src/Core/Models/TwoFactorProvider.cs b/src/Core/Models/TwoFactorProvider.cs index 1b74bc2a5c..79d23c5226 100644 --- a/src/Core/Models/TwoFactorProvider.cs +++ b/src/Core/Models/TwoFactorProvider.cs @@ -1,4 +1,5 @@ -using Newtonsoft.Json; +using Bit.Core.Enums; +using Newtonsoft.Json; using System; using System.Collections.Generic; using U2F.Core.Utils; @@ -38,5 +39,18 @@ namespace Bit.Core.Models public uint Counter { get; set; } public bool Compromised { get; set; } } + + public static bool RequiresPremium(TwoFactorProviderType type) + { + switch(type) + { + case TwoFactorProviderType.Duo: + case TwoFactorProviderType.YubiKey: + case TwoFactorProviderType.U2f: + return true; + default: + return false; + } + } } }