private List <Tuple <string, TwoFactorProvider.U2fMetaData> > LoadKeys(TwoFactorProvider provider) { var keys = new List <Tuple <string, TwoFactorProvider.U2fMetaData> >(); if (!HasProperMetaData(provider)) { return(keys); } // Support up to 5 keys for (var i = 1; i <= 5; i++) { var keyName = $"Key{i}"; if (provider.MetaData.ContainsKey(keyName)) { var key = new TwoFactorProvider.U2fMetaData((dynamic)provider.MetaData[keyName]); if (!key?.Compromised ?? false) { keys.Add(new Tuple <string, TwoFactorProvider.U2fMetaData>(keyName, key)); } } } return(keys); }
public async Task <bool> TwoFactorIsEnabledAsync(ITwoFactorProvidersUser user) { var providers = user.GetTwoFactorProviders(); if (providers == null) { return(false); } foreach (var p in providers) { if (p.Value?.Enabled ?? false) { if (!TwoFactorProvider.RequiresPremium(p.Key)) { return(true); } if (await CanAccessPremium(user)) { return(true); } } } return(false); }
public bool TwoFactorIsEnabled() { var providers = GetTwoFactorProviders(); if (providers == null) { return(false); } return(providers.Any(p => (p.Value?.Enabled ?? false) && (Premium || !TwoFactorProvider.RequiresPremium(p.Key)))); }
public bool TwoFactorProviderIsEnabled(TwoFactorProviderType provider) { var providers = GetTwoFactorProviders(); if (providers == null || !providers.ContainsKey(provider)) { return(false); } return(providers[provider].Enabled && (Premium || !TwoFactorProvider.RequiresPremium(provider))); }
public TwoFactorProviderResponseModel(TwoFactorProviderType type, TwoFactorProvider provider) : base(ResponseObj) { if (provider == null) { throw new ArgumentNullException(nameof(provider)); } Enabled = provider.Enabled; Type = type; }
private async Task <Dictionary <string, object> > BuildTwoFactorParams(User user, TwoFactorProviderType type, TwoFactorProvider provider) { if (!user.TwoFactorProviderIsEnabled(type)) { return(null); } switch (type) { case TwoFactorProviderType.Duo: case TwoFactorProviderType.U2f: case TwoFactorProviderType.Email: case TwoFactorProviderType.YubiKey: var token = await _userManager.GenerateTwoFactorTokenAsync(user, type.ToString()); if (type == TwoFactorProviderType.Duo) { return(new Dictionary <string, object> { ["Host"] = provider.MetaData["Host"], ["Signature"] = token }); } else if (type == TwoFactorProviderType.U2f) { return(new Dictionary <string, object> { ["Challenges"] = token }); } else if (type == TwoFactorProviderType.Email) { return(new Dictionary <string, object> { ["Email"] = RedactEmail((string)provider.MetaData["Email"]) }); } else if (type == TwoFactorProviderType.YubiKey) { return(new Dictionary <string, object> { ["Nfc"] = (bool)provider.MetaData["Nfc"] }); } return(null); default: return(null); } }
public TwoFactorU2fResponseModel(User user, TwoFactorProvider provider, U2fRegistration registration = null) : base("twoFactorU2f") { if (user == null) { throw new ArgumentNullException(nameof(user)); } if (registration != null) { Challenge = new ChallengeModel(user, registration); } Enabled = provider?.Enabled ?? false; }
public async Task <CredentialCreateOptions> StartWebAuthnRegistrationAsync(User user) { var providers = user.GetTwoFactorProviders(); if (providers == null) { providers = new Dictionary <TwoFactorProviderType, TwoFactorProvider>(); } var provider = user.GetTwoFactorProvider(TwoFactorProviderType.WebAuthn); if (provider == null) { provider = new TwoFactorProvider { Enabled = false }; } if (provider.MetaData == null) { provider.MetaData = new Dictionary <string, object>(); } var fidoUser = new Fido2User { DisplayName = user.Name, Name = user.Email, Id = user.Id.ToByteArray(), }; var excludeCredentials = provider.MetaData .Where(k => k.Key.StartsWith("Key")) .Select(k => new TwoFactorProvider.WebAuthnData((dynamic)k.Value).Descriptor) .ToList(); var authenticatorSelection = new AuthenticatorSelection { AuthenticatorAttachment = null, RequireResidentKey = false, UserVerification = UserVerificationRequirement.Discouraged }; var options = _fido2.RequestNewCredential(fidoUser, excludeCredentials, authenticatorSelection, AttestationConveyancePreference.None); provider.MetaData["pending"] = options.ToJson(); providers[TwoFactorProviderType.WebAuthn] = provider; user.SetTwoFactorProviders(providers); await UpdateTwoFactorProviderAsync(user, TwoFactorProviderType.WebAuthn, false); return(options); }
public async Task <bool> TwoFactorProviderIsEnabledAsync(TwoFactorProviderType provider, ITwoFactorProvidersUser user) { var providers = user.GetTwoFactorProviders(); if (providers == null || !providers.ContainsKey(provider) || !providers[provider].Enabled) { return(false); } if (!TwoFactorProvider.RequiresPremium(provider)) { return(true); } return(await CanAccessPremium(user)); }
private void Build(TwoFactorProvider provider) { if (provider?.MetaData != null && provider.MetaData.Count > 0) { Enabled = provider.Enabled; if (provider.MetaData.ContainsKey("Host")) { Host = (string)provider.MetaData["Host"]; } if (provider.MetaData.ContainsKey("SKey")) { SecretKey = (string)provider.MetaData["SKey"]; } if (provider.MetaData.ContainsKey("IKey")) { IntegrationKey = (string)provider.MetaData["IKey"]; } } else { Enabled = false; } }
private async Task <Dictionary <string, object> > BuildTwoFactorParams(Organization organization, User user, TwoFactorProviderType type, TwoFactorProvider provider) { switch (type) { case TwoFactorProviderType.Duo: case TwoFactorProviderType.WebAuthn: case TwoFactorProviderType.Email: case TwoFactorProviderType.YubiKey: if (!(await _userService.TwoFactorProviderIsEnabledAsync(type, user))) { return(null); } var token = await _userManager.GenerateTwoFactorTokenAsync(user, CoreHelpers.CustomProviderName(type)); if (type == TwoFactorProviderType.Duo) { return(new Dictionary <string, object> { ["Host"] = provider.MetaData["Host"], ["Signature"] = token }); } else if (type == TwoFactorProviderType.WebAuthn) { if (token == null) { return(null); } return(JsonSerializer.Deserialize <Dictionary <string, object> >(token)); } else if (type == TwoFactorProviderType.Email) { return(new Dictionary <string, object> { ["Email"] = token }); } else if (type == TwoFactorProviderType.YubiKey) { return(new Dictionary <string, object> { ["Nfc"] = (bool)provider.MetaData["Nfc"] }); } return(null); case TwoFactorProviderType.OrganizationDuo: if (await _organizationDuoWebTokenProvider.CanGenerateTwoFactorTokenAsync(organization)) { return(new Dictionary <string, object> { ["Host"] = provider.MetaData["Host"], ["Signature"] = await _organizationDuoWebTokenProvider.GenerateAsync(organization, user) }); } return(null); default: return(null); } }
private bool HasProperMetaData(TwoFactorProvider provider) { return(provider?.MetaData?.Any() ?? false); }
private bool HasProperMetaData(TwoFactorProvider provider) { return((provider?.MetaData?.Count ?? 0) > 0); }
public async Task <bool> CompleteU2fRegistrationAsync(User user, int id, string name, string deviceResponse) { if (string.IsNullOrWhiteSpace(deviceResponse)) { return(false); } var challenges = await _u2fRepository.GetManyByUserIdAsync(user.Id); if (!challenges?.Any() ?? true) { return(false); } var registerResponse = BaseModel.FromJson <RegisterResponse>(deviceResponse); try { var challenge = challenges.OrderBy(i => i.Id).Last(i => i.KeyHandle == null); var startedReg = new StartedRegistration(challenge.Challenge, challenge.AppId); var reg = U2fLib.FinishRegistration(startedReg, registerResponse); await _u2fRepository.DeleteManyByUserIdAsync(user.Id); // Add device var providers = user.GetTwoFactorProviders(); if (providers == null) { providers = new Dictionary <TwoFactorProviderType, TwoFactorProvider>(); } var provider = user.GetTwoFactorProvider(TwoFactorProviderType.U2f); if (provider == null) { provider = new TwoFactorProvider(); } if (provider.MetaData == null) { provider.MetaData = new Dictionary <string, object>(); } if (provider.MetaData.Count >= 5) { // Can only register up to 5 keys return(false); } var keyId = $"Key{id}"; if (provider.MetaData.ContainsKey(keyId)) { provider.MetaData.Remove(keyId); } provider.Enabled = true; provider.MetaData.Add(keyId, new TwoFactorProvider.U2fMetaData { Name = name, KeyHandle = reg.KeyHandle == null ? null : Utils.ByteArrayToBase64String(reg.KeyHandle), PublicKey = reg.PublicKey == null ? null : Utils.ByteArrayToBase64String(reg.PublicKey), Certificate = reg.AttestationCert == null ? null : Utils.ByteArrayToBase64String(reg.AttestationCert), Compromised = false, Counter = reg.Counter }); if (providers.ContainsKey(TwoFactorProviderType.U2f)) { providers.Remove(TwoFactorProviderType.U2f); } providers.Add(TwoFactorProviderType.U2f, provider); user.SetTwoFactorProviders(providers); await UpdateTwoFactorProviderAsync(user, TwoFactorProviderType.U2f); return(true); } catch (U2fException e) { Logger.LogError(e, "Complete U2F registration error."); return(false); } }
public async Task<TwoFactorResponseModel> GetTwoFactor(string masterPasswordHash, TwoFactorProvider provider) { var user = _currentContext.User; if(!await _userManager.CheckPasswordAsync(user, masterPasswordHash)) { await Task.Delay(2000); throw new BadRequestException("MasterPasswordHash", "Invalid password."); } await _userService.GetTwoFactorAsync(user, provider); var response = new TwoFactorResponseModel(user); return response; }
private bool HasProperMetaData(TwoFactorProvider provider) { return(provider?.MetaData != null && provider.MetaData.ContainsKey("Email") && !string.IsNullOrWhiteSpace((string)provider.MetaData["Email"])); }
public string ProvideScript(Func <IDbCommand> commandFactory) { var cmd = commandFactory(); cmd.CommandText = "SELECT Id, TwoFactorProviders FROM [dbo].[User] WHERE TwoFactorProviders IS NOT NULL"; var users = new List <object>(); using (var reader = cmd.ExecuteReader()) { while (reader.Read()) { var id = reader.GetGuid(0); var twoFactorProviders = reader.GetString(1); if (string.IsNullOrWhiteSpace(twoFactorProviders)) { continue; } var providers = JsonConvert.DeserializeObject <Dictionary <TwoFactorProviderType, TwoFactorProvider> >(twoFactorProviders); if (!providers.ContainsKey(TwoFactorProviderType.U2f)) { continue; } var u2fProvider = providers[TwoFactorProviderType.U2f]; if (!u2fProvider.Enabled || !HasProperMetaData(u2fProvider)) { continue; } var u2fKeys = LoadKeys(u2fProvider); var webAuthnKeys = u2fKeys.Select(key => (key.Item1, key.Item2.ToWebAuthnData())); var webAuthnProvider = new TwoFactorProvider { Enabled = true, MetaData = webAuthnKeys.ToDictionary(x => x.Item1, x => (object)x.Item2) }; providers[TwoFactorProviderType.WebAuthn] = webAuthnProvider; users.Add(new User { Id = id, TwoFactorProviders = JsonConvert.SerializeObject(providers), }); } } foreach (User user in users) { var command = commandFactory(); command.CommandText = "UPDATE [dbo].[User] SET TwoFactorProviders = @twoFactorProviders WHERE Id = @id"; var idParameter = command.CreateParameter(); idParameter.ParameterName = "@id"; idParameter.Value = user.Id; var twoFactorParameter = command.CreateParameter(); twoFactorParameter.ParameterName = "@twoFactorProviders"; twoFactorParameter.Value = user.TwoFactorProviders; command.Parameters.Add(idParameter); command.Parameters.Add(twoFactorParameter); command.ExecuteNonQuery(); } return(""); }
private async Task <Dictionary <string, object> > BuildTwoFactorParams(Organization organization, User user, TwoFactorProviderType type, TwoFactorProvider provider) { switch (type) { case TwoFactorProviderType.Duo: case TwoFactorProviderType.U2f: case TwoFactorProviderType.Email: case TwoFactorProviderType.YubiKey: if (!(await user.TwoFactorProviderIsEnabledAsync(type, _userService))) { return(null); } var token = await _userManager.GenerateTwoFactorTokenAsync(user, type.ToString()); if (type == TwoFactorProviderType.Duo) { return(new Dictionary <string, object> { ["Host"] = provider.MetaData["Host"], ["Signature"] = token }); } else if (type == TwoFactorProviderType.U2f) { // TODO: Remove "Challenges" in a future update. Deprecated. var tokens = token?.Split('|'); return(new Dictionary <string, object> { ["Challenge"] = tokens != null && tokens.Length > 0 ? tokens[0] : null, ["Challenges"] = tokens != null && tokens.Length > 1 ? tokens[1] : null }); } else if (type == TwoFactorProviderType.Email) { return(new Dictionary <string, object> { ["Email"] = RedactEmail((string)provider.MetaData["Email"]) }); } else if (type == TwoFactorProviderType.YubiKey) { return(new Dictionary <string, object> { ["Nfc"] = (bool)provider.MetaData["Nfc"] }); } return(null); case TwoFactorProviderType.OrganizationDuo: if (await _organizationDuoWebTokenProvider.CanGenerateTwoFactorTokenAsync(organization)) { return(new Dictionary <string, object> { ["Host"] = provider.MetaData["Host"], ["Signature"] = await _organizationDuoWebTokenProvider.GenerateAsync(organization, user) }); } return(null); default: return(null); } }
protected async Task BuildTwoFactorResultAsync(User user, Organization organization, T context, bool requires2FABecauseNewDevice) { var providerKeys = new List <byte>(); var providers = new Dictionary <string, Dictionary <string, object> >(); var enabledProviders = new List <KeyValuePair <TwoFactorProviderType, TwoFactorProvider> >(); if (organization?.GetTwoFactorProviders() != null) { enabledProviders.AddRange(organization.GetTwoFactorProviders().Where( p => organization.TwoFactorProviderIsEnabled(p.Key))); } if (user.GetTwoFactorProviders() != null) { foreach (var p in user.GetTwoFactorProviders()) { if (await _userService.TwoFactorProviderIsEnabledAsync(p.Key, user)) { enabledProviders.Add(p); } } } if (!enabledProviders.Any()) { if (!requires2FABecauseNewDevice) { await BuildErrorResultAsync("No two-step providers enabled.", false, context, user); return; } var emailProvider = new TwoFactorProvider { MetaData = new Dictionary <string, object> { ["Email"] = user.Email.ToLowerInvariant() }, Enabled = true }; enabledProviders.Add(new KeyValuePair <TwoFactorProviderType, TwoFactorProvider>( TwoFactorProviderType.Email, emailProvider)); user.SetTwoFactorProviders(new Dictionary <TwoFactorProviderType, TwoFactorProvider> { [TwoFactorProviderType.Email] = emailProvider }); } foreach (var provider in enabledProviders) { providerKeys.Add((byte)provider.Key); var infoDict = await BuildTwoFactorParams(organization, user, provider.Key, provider.Value); providers.Add(((byte)provider.Key).ToString(), infoDict); } SetTwoFactorResult(context, new Dictionary <string, object> { { "TwoFactorProviders", providers.Keys }, { "TwoFactorProviders2", providers } }); if (enabledProviders.Count() == 1 && enabledProviders.First().Key == TwoFactorProviderType.Email) { // Send email now if this is their only 2FA method await _userService.SendTwoFactorEmailAsync(user, requires2FABecauseNewDevice); } }
private bool HasProperMetaData(TwoFactorProvider provider) { return(provider?.MetaData != null && provider.MetaData.ContainsKey("Key1")); }
public async Task <TwoFactorResponseModel> GetTwoFactor(string masterPasswordHash, TwoFactorProvider provider) { var user = _currentContext.User; if (!await _userManager.CheckPasswordAsync(user, masterPasswordHash)) { await Task.Delay(2000); throw new BadRequestException("MasterPasswordHash", "Invalid password."); } await _userService.GetTwoFactorAsync(user, provider); var response = new TwoFactorResponseModel(user); return(response); }