public async Task <ActionResult> SignInOptions([FromForm] string username) { try { var user = await oktaClient.Users.GetUserAsync(username); if (user == null) { throw new ArgumentException("Username was not registered"); } var credential = JsonConvert.DeserializeObject <StoredCredential>(user.Profile["PasswordlessPublicKey"].ToString()); var options = fido2.GetAssertionOptions(new List <PublicKeyCredentialDescriptor> { credential.Descriptor }, UserVerificationRequirement.Discouraged); HttpContext.Session.SetString("fido2.assertionOptions", options.ToJson()); return(Json(options)); } catch (Exception e) { return(Json(new AssertionOptions { Status = "error", ErrorMessage = e.Message })); } }
/// <summary> /// 断言:创建断言选项 /// <para> 当用户想要登录时,我们会根据注册的凭据进行断言。</para> /// </summary> public async Task <AssertionOptions> AssertionOptionsPost(User user, AssertionClientParams assertionClientParams) { string error = ""; // 1. Get user from DB if (user == null) { error = "username was not registered"; var ass = new AssertionOptions() { Status = "bad", ErrorMessage = error }; return(ass); } // 2. Get registered credentials from database var existingCredentials = GetPublicKeyCredentialDescriptors(user.UserId); var options = _fido2.GetAssertionOptions( existingCredentials, assertionClientParams.UserVerification, assertionClientParams.Extensions ); distributedCache.SetString(user.UserId.ToString() + "assertionOptions", options.ToJson(), 120); return(options); }
public static Maybe <AssertionOptions> GenerateAssertionOptionsForUser(this IFido2 fido2, IUser user) { var existingCredentials = user.AuthenticatorDevices.Select(x => new PublicKeyCredentialDescriptor(x.CredentialId)); try { var exts = new AuthenticationExtensionsClientInputs { SimpleTransactionAuthorization = "FIDO", GenericTransactionAuthorization = new TxAuthGenericArg { ContentType = "text/plain", Content = new byte[] { 0x46, 0x49, 0x44, 0x4F }, }, UserVerificationIndex = true, Location = true, UserVerificationMethod = true, }; var uv = UserVerificationRequirement.Discouraged; var options = fido2.GetAssertionOptions( existingCredentials, uv, exts); return(Maybe.From(options)); } catch (Fido2VerificationException) { return(Maybe <AssertionOptions> .Nothing); } }
public ActionResult AssertionOptionsPost([FromForm] string username, [FromForm] string userVerification) { try { var existingCredentials = new List <PublicKeyCredentialDescriptor>(); if (!string.IsNullOrEmpty(username)) { // 1. Get user from DB var user = fidoStore.GetUser(username); if (user == null) { throw new ArgumentException("Username was not registered"); } // 2. Get registered credentials from database existingCredentials = fidoStore.GetCredentialsByUser(user).Select(c => c.Descriptor).ToList(); } var exts = new AuthenticationExtensionsClientInputs() { SimpleTransactionAuthorization = "FIDO", GenericTransactionAuthorization = new TxAuthGenericArg { ContentType = "text/plain", Content = new byte[] { 0x46, 0x49, 0x44, 0x4F } }, UserVerificationIndex = true, Location = true, UserVerificationMethod = true }; // 3. Create options var uv = string.IsNullOrEmpty(userVerification) ? UserVerificationRequirement.Discouraged : userVerification.ToEnum <UserVerificationRequirement>(); var options = fido2.GetAssertionOptions( existingCredentials, uv, exts ); // 4. Temporarily store options, session/in-memory cache/redis/db HttpContext.Session.SetString("fido2.assertionOptions", options.ToJson()); // 5. Return options to client return(Ok(options)); } catch (Exception e) { return(BadRequest(new AssertionOptions { Status = "error", ErrorMessage = FormatException(e) })); } }
public async Task <IActionResult> AssertionOptionsPost(AssertionOptionsModel model) { try { var existingCredentials = new List <PublicKeyCredentialDescriptor>(); if (!string.IsNullOrEmpty(model.UserName)) { // 1. Get user from DB var user = await context.Members.Where(x => x.UserName == model.UserName).FirstOrDefaultAsync(); if (user == null) { return(BadRequest("Username was not registered")); } // 2. Get registered credentials from database existingCredentials = await context.StoredCredentials.Where(x => x.UserId == user.UserId).Select(m => m.Descriptor).ToListAsync(); } var exts = new AuthenticationExtensionsClientInputs() { SimpleTransactionAuthorization = "Could you please verify yourself?", GenericTransactionAuthorization = new TxAuthGenericArg { ContentType = "text/plain", Content = new byte[] { 0x46, 0x49, 0x44, 0x4F } }, UserVerificationIndex = true, Location = true, UserVerificationMethod = true }; // 3. Create options var uv = string.IsNullOrEmpty(model.UserVerification) ? UserVerificationRequirement.Discouraged : model.UserVerification.ToEnum <UserVerificationRequirement>(); var options = _fido2.GetAssertionOptions( existingCredentials, uv, exts ); // 4. Temporarily store options, session/in-memory cache/redis/db HttpContext.Session.SetString("fido2.assertionOptions", options.ToJson()); // 5. Return options to client return(Ok(options)); } catch (Exception e) { return(BadRequest(new AssertionOptions { Status = "error", ErrorMessage = FormatException(e) })); } }
public Result <AssertionOptions> MakeAssertionOptions(string username) { try { List <DeviceAuthorization> existingAuthorizations = null; if (username != null) { // 1. Get registered credentials from database existingAuthorizations = _db.Users .AsNoTracking() .Include(x => x.DeviceAuthorizations) .SingleOrDefault(x => x.Username == username) ?.DeviceAuthorizations; if (existingAuthorizations is null || existingAuthorizations.Count == 0) { return(Result.Failure <AssertionOptions>("No existing credentials")); } } // 2. Create options //var extensions = new AuthenticationExtensionsClientInputs() //{ // SimpleTransactionAuthorization = "FIDO", // GenericTransactionAuthorization = new TxAuthGenericArg // { // ContentType = "text/plain", // Content = new byte[] { 0x46, 0x49, 0x44, 0x4F } // }, // UserVerificationIndex = true, // Location = true, // UserVerificationMethod = true //} var options = _fido2.GetAssertionOptions( existingAuthorizations?.Select(x => new PublicKeyCredentialDescriptor(x.CredentialId)), UserVerificationRequirement.Preferred ); // 3. Temporarily store options var anonymousOptions = _mapper.Map <AnonymousAssertionOptions>(options); anonymousOptions.RequestId = Guid.NewGuid().ToString(); _cache.Set($"AssertionOptions:{anonymousOptions.RequestId}", options, _options.Value.ChallengeExpiration); options = anonymousOptions; // 4. Return options to client return(Result.Success(options)); } catch (Exception e) { _logger.LogError(e, $"Failed to make assertion options for user {username}"); return(Result.Failure <AssertionOptions>("Error starting assertion")); } }
public async Task <ActionResult> AssertionOptionsPost([FromForm] string username, [FromForm] string userVerification) { try { var existingCredentials = new List <PublicKeyCredentialDescriptor>(); // 1. Get user from DB var signInUser = await _signInManager.GetTwoFactorAuthenticationUserAsync(); var applicationUser = await _userManager.FindByNameAsync(signInUser.UserName); // 2. Get registered credentials from database var creds = await _fido2CredentialService.GetCredentialsByUser(applicationUser); existingCredentials = creds.Select(c => new PublicKeyCredentialDescriptor(c.Descriptor)).ToList(); var exts = new AuthenticationExtensionsClientInputs() { SimpleTransactionAuthorization = "FIDO", GenericTransactionAuthorization = new TxAuthGenericArg { ContentType = "text/plain", Content = new byte[] { 0x46, 0x49, 0x44, 0x4F } }, UserVerificationIndex = true, Location = true, UserVerificationMethod = true }; // 3. Create options var uv = string.IsNullOrEmpty(userVerification) ? UserVerificationRequirement.Discouraged : userVerification.ToEnum <UserVerificationRequirement>(); var options = _fido2.GetAssertionOptions( existingCredentials, uv, exts ); // 4. Temporarily store options, session/in-memory cache/redis/db HttpContext.Session.SetString("fido2.assertionOptions", options.ToJson()); // 5. Return options to client return(Json(options)); } catch (Exception e) { return(Json(new AssertionOptions { Status = "error", ErrorMessage = FormatException(e) })); } }
public async Task <AssertionOptions> RequestLogin(string userId) { await using var dbContext = _contextFactory.CreateContext(); var user = await dbContext.Users.Include(applicationUser => applicationUser.Fido2Credentials) .FirstOrDefaultAsync(applicationUser => applicationUser.Id == userId); if (!(user?.Fido2Credentials?.Any() is true)) { return(null); } var existingCredentials = user.Fido2Credentials .Where(credential => credential.Type == Fido2Credential.CredentialType.FIDO2) .Select(c => c.GetBlob().Descriptor) .ToList(); var exts = new AuthenticationExtensionsClientInputs() { SimpleTransactionAuthorization = "FIDO", GenericTransactionAuthorization = new TxAuthGenericArg { ContentType = "text/plain", Content = new byte[] { 0x46, 0x49, 0x44, 0x4F } }, UserVerificationIndex = true, Location = true, UserVerificationMethod = true, Extensions = true, AppID = _fido2Configuration.Origin }; // 3. Create options var options = _fido2.GetAssertionOptions( existingCredentials, UserVerificationRequirement.Discouraged, exts ); LoginStore.AddOrReplace(userId, options); return(options); }
public async Task <string> GenerateAsync(string purpose, UserManager <User> manager, User user) { var userService = _serviceProvider.GetRequiredService <IUserService>(); if (!(await userService.CanAccessPremium(user))) { return(null); } var provider = user.GetTwoFactorProvider(TwoFactorProviderType.WebAuthn); var keys = LoadKeys(provider); var existingCredentials = keys.Select(key => key.Item2.Descriptor).ToList(); if (existingCredentials.Count == 0) { return(null); } var exts = new AuthenticationExtensionsClientInputs() { UserVerificationMethod = true, AppID = CoreHelpers.U2fAppIdUrl(_globalSettings), }; var options = _fido2.GetAssertionOptions(existingCredentials, UserVerificationRequirement.Discouraged, exts); // TODO: Remove this when newtonsoft legacy converters are gone provider.MetaData["login"] = JsonSerializer.Serialize(options); var providers = user.GetTwoFactorProviders(); providers[TwoFactorProviderType.WebAuthn] = provider; user.SetTwoFactorProviders(providers); await userService.UpdateTwoFactorProviderAsync(user, TwoFactorProviderType.WebAuthn, logEvent : false); return(options.ToJson()); }