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 = PasswordlessStore.GetUser(username); if (user == null) { throw new ArgumentException("Username was not registered"); } // 2. Get registered credentials from database existingCredentials = PasswordlessStore.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(Json(options)); } catch (Exception e) { return(Json(new AssertionOptions { Status = "error", ErrorMessage = FormatException(e) })); } }
public JsonResult MakeCredentialOptions([FromForm] string username, [FromForm] string displayName, [FromForm] string attType, [FromForm] string authType, [FromForm] bool requireResidentKey, [FromForm] string userVerification) { try { if (string.IsNullOrEmpty(username)) { username = $"{displayName} (Usernameless user created at {DateTime.UtcNow})"; } // 1. Get user from DB by username (in our example, auto create missing users) var user = DemoStorage.GetOrAddUser(username, () => new Fido2User { DisplayName = displayName, Name = username, Id = Encoding.UTF8.GetBytes(username) // byte representation of userID is required }); // 2. Get user existing keys by username var existingKeys = DemoStorage.GetCredentialsByUser(user).Select(c => c.Descriptor).ToList(); // 3. Create options var authenticatorSelection = new AuthenticatorSelection { RequireResidentKey = requireResidentKey, UserVerification = userVerification.ToEnum <UserVerificationRequirement>() }; if (!string.IsNullOrEmpty(authType)) { authenticatorSelection.AuthenticatorAttachment = authType.ToEnum <AuthenticatorAttachment>(); } var exts = new AuthenticationExtensionsClientInputs() { Extensions = true, UserVerificationIndex = true, Location = true, UserVerificationMethod = true, BiometricAuthenticatorPerformanceBounds = new AuthenticatorBiometricPerfBounds { FAR = float.MaxValue, FRR = float.MaxValue } }; var options = _fido2.RequestNewCredential(user, existingKeys, authenticatorSelection, attType.ToEnum <AttestationConveyancePreference>(), exts); // 4. Temporarily store options, session/in-memory cache/redis/db HttpContext.Session.SetString("fido2.attestationOptions", options.ToJson()); // 5. return options to client return(Json(options)); } catch (Exception e) { return(Json(new CredentialCreateOptions { Status = "error", ErrorMessage = FormatException(e) })); } }
public AssertionOptionsResponse GetAssertionOptions([FromBody][Required] AssertionOptionsRequest request) { using (AuthLogic.Disable()) { var existingCredentials = new List <PublicKeyCredentialDescriptor>(); if (!string.IsNullOrEmpty(request.UserName)) { existingCredentials = Database.Query <WebAuthnCredentialEntity>() .Where(a => a.User.Entity.UserName == request.UserName) .Select(a => new PublicKeyCredentialDescriptor(a.CredentialId)) .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 = UserVerificationRequirement.Discouraged; var options = fido2.GetAssertionOptions( existingCredentials, uv, exts ); if (options.Status != "ok") { throw new InvalidOperationException(options.ErrorMessage); } Database.Query <WebAuthnAssertionOptionsEntity>().Where(a => a.CreationDate < DateTime.Now.AddMonths(-1)).UnsafeDelete(); var optionsEntity = new WebAuthnAssertionOptionsEntity { Json = options.ToJson() }.Save(); return(new AssertionOptionsResponse { AssertionOptions = options, AssertionOptionsId = (Guid)optionsEntity.Id }); } }
public IActionResult AssertionOptionsTest([FromBody] TEST_AssertionClientParams assertionClientParams) { var username = assertionClientParams.Username; // 1. Get user from DB var user = DemoStorage.GetUser(username); if (user == null) { return(NotFound("username was not registered")); } // 2. Get registered credentials from database var existingCredentials = DemoStorage.GetCredentialsByUser(user).Select(c => c.Descriptor).ToList(); var uv = assertionClientParams.UserVerification; if (null != assertionClientParams.authenticatorSelection) { uv = assertionClientParams.authenticatorSelection.UserVerification; } var exts = new AuthenticationExtensionsClientInputs { AppID = _origin, SimpleTransactionAuthorization = "FIDO", GenericTransactionAuthorization = new TxAuthGenericArg { ContentType = "text/plain", Content = new byte[] { 0x46, 0x49, 0x44, 0x4F } }, UserVerificationIndex = true, Location = true, UserVerificationMethod = true }; if (null != assertionClientParams.Extensions && null != assertionClientParams.Extensions.Example) { exts.Example = assertionClientParams.Extensions.Example; } // 3. Create options var options = _fido2.GetAssertionOptions( existingCredentials, uv, exts ); // 4. Temporarily store options, session/in-memory cache/redis/db HttpContext.Session.SetString("fido2.assertionOptions", options.ToJson()); HttpContext.Session.SetString("fido2.assertionOptions.origin", _origin); // 5. Return options to client return(Json(options)); }
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 <ActionResult> AssertionOptions([FromForm] string email, [FromForm] string userVerification) { try { var user = !string.IsNullOrEmpty(email) ? await _userManager.FindByEmailAsync(email) : null; if (user == null) { return(NotFound()); } var existingCredentials = await _auth.GetCredentialsForUser(user.Id); 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 ); // 5. Return options to client return(Json(new { allowCredentials = options.AllowCredentials, challenge = options.Challenge, extensions = options.Extensions, error = options.ErrorMessage, status = options.Status, timeout = options.Timeout, userVerification = options.UserVerification?.ToString()?.ToLower() })); } catch (Exception e) { return(Json(new AssertionOptions { Status = "error", ErrorMessage = e.Message })); } }
/// <summary> /// Returns AssertionOptions including a challenge to the browser/authr to assert existing credentials and authenticate a user. /// </summary> /// <returns></returns> public AssertionOptions GetAssertionOptions( IEnumerable <PublicKeyCredentialDescriptor> allowedCredentials, UserVerificationRequirement?userVerification, AuthenticationExtensionsClientInputs extensions = null) { var challenge = new byte[_config.ChallengeSize]; _crypto.GetBytes(challenge); var options = AssertionOptions.Create(_config, challenge, allowedCredentials, userVerification, extensions); return(options); }
public async Task <IActionResult> MakeCredentialOptions([FromBody] MakeCredentialOptionsRequest request) { try { var user = _dataStore.AddUser(request.Username, () => new Fido2User { DisplayName = request.DisplayName, Name = request.Username, Id = Encoding.UTF8.GetBytes(request.Username) }); var existingKeys = _dataStore.GetCredentialsByUser(user).Select(c => c.Descriptor).ToList(); var authenticatorSelection = new AuthenticatorSelection { RequireResidentKey = request.RequireResidentKey, UserVerification = request.UserVerification.ToEnum <UserVerificationRequirement>() }; if (!string.IsNullOrEmpty(request.AuthType)) { authenticatorSelection.AuthenticatorAttachment = request.AuthType.ToEnum <AuthenticatorAttachment>(); } var authenticationExtensionsClientInputs = new AuthenticationExtensionsClientInputs { Extensions = true, UserVerificationIndex = true, Location = true, UserVerificationMethod = true, BiometricAuthenticatorPerformanceBounds = new AuthenticatorBiometricPerfBounds { FAR = float.MaxValue, FRR = float.MaxValue } }; var options = _lib.RequestNewCredential(user, existingKeys, authenticatorSelection, request.AttType.ToEnum <AttestationConveyancePreference>(), authenticationExtensionsClientInputs); _memoryCache.Set(Base64Url.Encode(options.Challenge), options.ToJson()); var ev = new Event(request.Username, "Successfully made credential options", nameof(RegistrationController), nameof(MakeCredentialOptions)); await _elasticClient.IndexAsync(ev, i => i.Index(GetIndexName(nameof(Ok)))); return(Ok(options)); } catch (Exception e) { var errorEvent = new ErrorEvent(e, request.Username, nameof(RegistrationController), nameof(MakeCredentialOptions)); await _elasticClient.IndexAsync(errorEvent, i => i.Index(GetIndexName(nameof(Exception)))); return(Ok(new CredentialCreateOptions { Status = "error", ErrorMessage = FormatException(e) })); } }
/// <summary> /// Returns CredentialCreateOptions including a challenge to be sent to the browser/authr to create new credentials /// </summary> /// <returns></returns> /// <param name="attestationPreference">This member is intended for use by Relying Parties that wish to express their preference for attestation conveyance. The default is none.</param> /// <param name="excludeCredentials">Recommended. This member is intended for use by Relying Parties that wish to limit the creation of multiple credentials for the same account on a single authenticator.The client is requested to return an error if the new credential would be created on an authenticator that also contains one of the credentials enumerated in this parameter.</param> public CredentialCreateOptions RequestNewCredential( Fido2User user, List <PublicKeyCredentialDescriptor> excludeCredentials, AuthenticatorSelection authenticatorSelection, AttestationConveyancePreference attestationPreference, AuthenticationExtensionsClientInputs extensions = null) { var challenge = new byte[_config.ChallengeSize]; _crypto.GetBytes(challenge); var options = CredentialCreateOptions.Create(_config, challenge, user, authenticatorSelection, attestationPreference, excludeCredentials, extensions); return(options); }
public async Task <IActionResult> AssertionOptions([FromForm] string username, [FromForm] string userVerification) { try { var existingCredentials = new List <PublicKeyCredentialDescriptor>(); if (!string.IsNullOrEmpty(username)) { var user = _dataStore.GetUser(username); if (user == null) { throw new ArgumentException("Username was not registered"); } existingCredentials = _dataStore.GetCredentialsByUser(user).Select(c => c.Descriptor).ToList(); } var authenticationExtensionsClientInputs = 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 = string.IsNullOrEmpty(userVerification) ? UserVerificationRequirement.Required : userVerification.ToEnum <UserVerificationRequirement>(); var options = _lib.GetAssertionOptions( existingCredentials, uv, authenticationExtensionsClientInputs ); _memoryCache.Set(Base64Url.Encode(options.Challenge), options.ToJson()); var ev = new Event(username, "Successfully made an options for assertion", nameof(AuthenticationController), nameof(AssertionOptions)); await _elasticClient.IndexAsync(ev, i => i.Index(GetIndexName(nameof(Ok)))); return(Ok(options)); } catch (Exception e) { var errorEvent = new ErrorEvent(e, username, nameof(AuthenticationController), nameof(AssertionOptions)); await _elasticClient.IndexAsync(errorEvent, i => i.Index(GetIndexName(nameof(Exception)))); return(Ok(new AssertionOptions { Status = "error", ErrorMessage = FormatException(e) })); } }
public async Task <CredentialCreateOptions> RequestCreation(string userId) { await using var dbContext = _contextFactory.CreateContext(); var user = await dbContext.Users.Include(applicationUser => applicationUser.Fido2Credentials) .FirstOrDefaultAsync(applicationUser => applicationUser.Id == userId); if (user == null) { return(null); } // 2. Get user existing keys by username var existingKeys = user.Fido2Credentials .Where(credential => credential.Type == Fido2Credential.CredentialType.FIDO2) .Select(c => c.GetFido2Blob().Descriptor).ToList(); // 3. Create options var authenticatorSelection = new AuthenticatorSelection { RequireResidentKey = false, UserVerification = UserVerificationRequirement.Preferred }; var exts = new AuthenticationExtensionsClientInputs() { Extensions = true, UserVerificationIndex = true, Location = true, UserVerificationMethod = true, BiometricAuthenticatorPerformanceBounds = new AuthenticatorBiometricPerfBounds { FAR = float.MaxValue, FRR = float.MaxValue }, }; var options = _fido2.RequestNewCredential( new Fido2User() { DisplayName = user.UserName, Name = user.UserName, Id = user.Id.ToBytesUTF8() }, existingKeys, authenticatorSelection, AttestationConveyancePreference.None, exts); // options.Rp = new PublicKeyCredentialRpEntity(Request.Host.Host, options.Rp.Name, ""); CreationStore.AddOrReplace(userId, options); return(options); }
public static string MakeWebAuthnAttestationRequest(Fido2Configuration fido2Config, byte[] challenge, LoginUsr LUser, List <PublicKeyCredentialDescriptor> excludedCredentials) { string usrId = LUser.UsrId.ToString(); string usrIdB64 = System.Convert.ToBase64String(usrId.ToUtf8ByteArray()); Fido2User user = new Fido2User { DisplayName = LUser.UsrName, /* must be restricted to no more than than 64 for device like yubikey as it would fail without reason */ //Name = (Guid.NewGuid().ToString() + " " + DateTime.UtcNow.ToString("o")).Left(64), //Id= Guid.NewGuid().ToString().ToUtf8ByteArray() Name = LUser.LoginName, Id = usrIdB64.ToUtf8ByteArray() }; AuthenticatorSelection authenticatorSelection = new AuthenticatorSelection { RequireResidentKey = false, UserVerification = UserVerificationRequirement.Discouraged, // AuthenticatorAttachment = AuthenticatorAttachment.Platform, }; AttestationConveyancePreference attConveyancePreference = AttestationConveyancePreference.None; AuthenticationExtensionsClientInputs clientExtensions = new AuthenticationExtensionsClientInputs { Extensions = true, SimpleTransactionAuthorization = string.Format("you are registering to {0}", fido2Config.ServerName), Location = true, UserVerificationMethod = true, BiometricAuthenticatorPerformanceBounds = new AuthenticatorBiometricPerfBounds { FAR = float.MaxValue, FRR = float.MaxValue } }; var fido2 = new Fido2(fido2Config); // must do this for the verification to work var options = fido2.RequestNewCredential(user, excludedCredentials, authenticatorSelection, attConveyancePreference, clientExtensions); // the challenge is random byte but we need more info, replace it options.Challenge = challenge; var createRequest = Fido2NetLib.CredentialCreateOptions.Create(fido2Config , challenge, user, authenticatorSelection, attConveyancePreference , excludedCredentials != null && excludedCredentials.Count > 0 ? excludedCredentials : null , clientExtensions); string createRequestJson = options.ToJson(); return(createRequestJson); }
/// <summary> /// GetLoginAssertionsOptions method implementation /// </summary> private string GetLoginAssertionsOptions(AuthenticationContext ctx) { try { List <MFAPublicKeyCredentialDescriptor> existingCredentials = new List <MFAPublicKeyCredentialDescriptor>(); if (!string.IsNullOrEmpty(ctx.UPN)) { var user = RuntimeRepository.GetUser(Config, ctx.UPN); if (user == null) { throw new ArgumentException("Username was not registered"); } existingCredentials = RuntimeRepository.GetCredentialsByUser(Config, user).Select(c => c.Descriptor).ToList(); } AuthenticationExtensionsClientInputs exts = new AuthenticationExtensionsClientInputs() { SimpleTransactionAuthorization = "FIDO", GenericTransactionAuthorization = new TxAuthGenericArg { ContentType = "text/plain", Content = new byte[] { 0x46, 0x49, 0x44, 0x4F } }, UserVerificationIndex = this.UserVerificationIndex, Location = this.Location, UserVerificationMethod = this.UserVerificationMethod, EnforceCredProtect = this.EnforceCredProtect, CredProtect = this.CredProtect, HmacSecret = this.HmacSecret }; UserVerificationRequirement uv = this.UserVerificationRequirement.ToEnum <UserVerificationRequirement>(); AssertionOptions options = _webathn.GetAssertionOptions(existingCredentials.ToCore(), uv, exts); string result = options.ToJson(); ctx.AssertionOptions = result; return(result); } catch (Exception e) { Log.WriteEntry(string.Format("{0}\r\n{1}", ctx.UPN, e.Message), EventLogEntryType.Error, 5000); string result = (new AssertionOptions { Status = "error", ErrorMessage = string.Format("{0}{1}", e.Message, e.InnerException != null ? " (" + e.InnerException.Message + ")" : "") }).ToJson(); ctx.AssertionOptions = result; return(result); } }
public async Task <IActionResult> FidoRegister(string button) { var sub = HttpContext.User.Claims.FirstOrDefault(x => x.Type == "sub")?.Value; if (string.IsNullOrEmpty(sub)) { return(RedirectToAction("Index", "Home")); } var user = await _users.FindByIdAsync(sub); if (user == null) { return(RedirectToAction("Index", "Home")); } var existingDbKeys = _authContext.FidoLogins.Where(x => x.UserId == user.Id).Select(x => x.PublicKeyIdBytes); var existingKeys = new List <PublicKeyCredentialDescriptor>(); foreach (var key in existingDbKeys) { existingKeys.Add(new PublicKeyCredentialDescriptor(key)); } var exts = new AuthenticationExtensionsClientInputs() { Extensions = true, UserVerificationIndex = true, Location = true, UserVerificationMethod = true, BiometricAuthenticatorPerformanceBounds = new AuthenticatorBiometricPerfBounds { FAR = float.MaxValue, FRR = float.MaxValue } }; Fido2User f2User = new Fido2User() { DisplayName = user.DisplayName, Id = System.Text.Encoding.ASCII.GetBytes(user.Id), Name = user.UserName }; var authSelect = new AuthenticatorSelection() { RequireResidentKey = false, UserVerification = UserVerificationRequirement.Preferred }; var options = _lib.RequestNewCredential(f2User, existingKeys, authSelect, AttestationConveyancePreference.Direct, exts); HttpContext.Session.SetString("fido2.attestationOptions", options.ToJson()); return(Json(options)); }
public JsonResult MakeCredentialOptionsTest([FromBody] TEST_MakeCredentialParams opts) { var attType = opts.Attestation; var username = new byte[] { }; try { username = Base64Url.Decode(opts.Username); } catch (FormatException) { username = Encoding.UTF8.GetBytes(opts.Username); } // 1. Get user from DB by username (in our example, auto create missing users) var user = DemoStorage.GetOrAddUser(opts.Username, () => new Fido2User { DisplayName = opts.DisplayName, Name = opts.Username, Id = username // byte representation of userID is required }); // 2. Get user existing keys by username var existingKeys = DemoStorage.GetCredentialsByUser(user).Select(c => c.Descriptor).ToList(); //var exts = new AuthenticationExtensionsClientInputs() { Extensions = true, UserVerificationIndex = true, Location = true, UserVerificationMethod = true, BiometricAuthenticatorPerformanceBounds = new AuthenticatorBiometricPerfBounds { FAR = float.MaxValue, FRR = float.MaxValue } }; var exts = new AuthenticationExtensionsClientInputs() { }; if (null != opts.Extensions && null != opts.Extensions.Example) { exts.Example = opts.Extensions.Example; } // 3. Create options var options = _fido2.RequestNewCredential(user, existingKeys, opts.AuthenticatorSelection, opts.Attestation, exts); // 4. Temporarily store options, session/in-memory cache/redis/db HttpContext.Session.SetString("fido2.attestationOptions", options.ToJson()); HttpContext.Session.SetString("fido2.attestationOptions.origin", _origin); // 5. return options to client return(Json(options)); }
/// <summary> /// GetLoginAssertionsOptions method implementation /// </summary> private string GetLoginAssertionsOptions(AuthenticationContext ctx) { try { List <MFAPublicKeyCredentialDescriptor> existingCredentials = new List <MFAPublicKeyCredentialDescriptor>(); if (!string.IsNullOrEmpty(ctx.UPN)) { var user = RuntimeRepository.GetUser(Config, ctx.UPN); if (user == null) { throw new ArgumentException("Username was not registered"); } existingCredentials = RuntimeRepository.GetCredentialsByUser(Config, user).Select(c => c.Descriptor).ToList(); } AuthenticationExtensionsClientInputs exts = new AuthenticationExtensionsClientInputs() { Extensions = this.Extentions, UserVerificationMethod = this.UserVerificationMethod, }; UserVerificationRequirement uv = this.UserVerificationRequirement; AssertionOptions options = null; if (existingCredentials.Count > 0) { options = _webathn.GetAssertionOptions(existingCredentials.ToCore(), uv, exts); } else { options = _webathn.GetAssertionOptions(null, uv, exts); } string result = options.ToJson(); ctx.AssertionOptions = result; return(result); } catch (Exception e) { Log.WriteEntry(string.Format("{0}\r\n{1}", ctx.UPN, e.Message), EventLogEntryType.Error, 5000); string result = (new AssertionOptions { Status = "error", ErrorMessage = string.Format("{0} / {1}", e.Message, e.InnerException != null ? " (" + e.InnerException.Message + ")" : "") }).ToJson(); ctx.AssertionOptions = result; return(result); } }
public IActionResult AssertionOptionsTest([FromBody] TEST_AssertionClientParams assertionClientParams) { var username = assertionClientParams.Username; // 1. Get user from DB var user = DemoStorage.GetUser(username); if (user == null) { return(NotFound("username was not registered")); } // 2. Get registered credentials from database var existingCredentials = DemoStorage.GetCredentialsByUser(user).Select(c => c.Descriptor).ToList(); var uv = assertionClientParams.UserVerification; if (null != assertionClientParams.authenticatorSelection) { uv = assertionClientParams.authenticatorSelection.UserVerification; } var exts = new AuthenticationExtensionsClientInputs() { Extensions = true, UserVerificationIndex = true, Location = true }; if (null != assertionClientParams.Extensions && null != assertionClientParams.Extensions.Example && 0 != assertionClientParams.Extensions.Example.Length) { exts.Example = assertionClientParams.Extensions.Example; } // 3. Create options var options = _lib.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)); }
public async Task <ActionResult> AssertionOptionsPost() { var data = await this._userQueries.GetDeviceInfoForCurrentUser(CancellationToken.None); var existingCredentials = data.Value.Entities.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 }; // 3. Create options var uv = UserVerificationRequirement.Discouraged; var options = this._fido2.GetAssertionOptions( existingCredentials, uv, exts); // 4. Temporarily store options, session/in-memory cache/redis/db this.TempData["fido2.assertionOptions"] = options.ToJson(); // 5. Return options to client return(this.Json(options)); } catch (Fido2VerificationException e) { return(this.Json(new AssertionOptions { Status = "error" })); } }
private AssertionOptions MakeFido2AssertionOptions(User user, string paymentId) { var fidoLogins = _authContext.FidoLogins.Where(x => x.UserId == user.Id); var existingKeys = new List <PublicKeyCredentialDescriptor>(); foreach (var key in fidoLogins) { existingKeys.Add(new PublicKeyCredentialDescriptor(key.PublicKeyIdBytes)); } //Getting data to sign var payment = _authContext.Payments.First(x => x.Id == paymentId); var payloadObj = new { paymentId = payment.Id, sub = payment.UserId, }; var payloadStr = JsonConvert.SerializeObject(payloadObj); var payload = Encoding.UTF8.GetBytes(payloadStr); var challenge = Fido2NetLib.Base64Url.Encode(payload); HttpContext.Session.SetString("fido2.assertionChallenge", challenge); HttpContext.Session.SetString("fido2.paymentId", paymentId); 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.Preferred; var options = _lib.GetAssertionOptions( existingKeys, uv, exts ); options.Challenge = Encoding.UTF8.GetBytes(challenge); // 4. Temporarily store options, session/in-memory cache/redis/db HttpContext.Session.SetString("fido2.assertionOptions", options.ToJson()); return(options); }
/// <summary> /// <para>注册:创建证明选项</para> /// <param name="opts"></param> /// <returns></returns> /// <exception cref="Exception"></exception> public CredentialCreateOptions MakeCredentialOptions(User user, MakeCredentialParams opts) { var fidoUser = opts.GetFido2UserByUser(); // Create options var exts = new AuthenticationExtensionsClientInputs() { Extensions = true, UserVerificationMethod = true, }; var existingKeys = GetPublicKeyCredentialDescriptors(user.UserId); var options = _fido2.RequestNewCredential( fidoUser, existingKeys, opts.AuthenticatorSelection, opts.Attestation, exts); distributedCache.SetString(user.UserId.ToString() + "attestationOptions", options.ToJson(), 120); return(options); }
public ActionResult AssertionOptionsPost([FromForm] string username) { try { // 1. Get user from DB var user = DemoStorage.GetUser(username); if (user == null) { throw new ArgumentException("Username was not registered"); } // 2. Get registered credentials from database var existingCredentials = DemoStorage.GetCredentialsByUser(user).Select(c => c.Descriptor).ToList(); var exts = new AuthenticationExtensionsClientInputs() { AppID = _origin, SimpleTransactionAuthorization = "demo!", UserVerificationIndex = true, Location = true }; // 3. Create options var options = _lib.GetAssertionOptions( existingCredentials, UserVerificationRequirement.Discouraged, 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 IActionResult Fido2LoginFailed() //{ // var returnUrl = HttpContext.Session.GetString("fido2.assertionOptions.returnUrl"); // var remLogStr = HttpContext.Session.GetString("fido2.assertionOptions.rememberLogin"); // var rememberLogin = string.IsNullOrEmpty(remLogStr) ? false : bool.Parse(remLogStr); // return RedirectToAction("Fido2Login", new { returnUrl, rememberLogin }); //} private async Task <AssertionOptions> PrepareFidoLogin(User user) { var claimsIdentity = new ClaimsIdentity(); claimsIdentity.AddClaim(new Claim(JwtClaimTypes.Subject, user.Id)); await HttpContext.SignInAsync(_fido2AuthenticationScheme, new ClaimsPrincipal(claimsIdentity)); var fidoLogins = _authenticationContext.FidoLogins.Where(x => x.UserId == user.Id).Select(x => x.PublicKeyIdBytes); if (fidoLogins.Count() < 1) { return(null); } var existingKeys = new List <PublicKeyCredentialDescriptor>(); foreach (var key in fidoLogins) { existingKeys.Add(new PublicKeyCredentialDescriptor(key)); } 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.Preferred; var options = _lib.GetAssertionOptions( existingKeys, uv, exts ); // 4. Temporarily store options, session/in-memory cache/redis/db HttpContext.Session.SetString("fido2.assertionOptions", options.ToJson()); return(options); }
public static string MakeWebAuthnAssertionRequest(Fido2Configuration fido2Config, byte[] challenge, List <PublicKeyCredentialDescriptor> allowedCredentials) { AuthenticatorSelection authSelection = new AuthenticatorSelection { RequireResidentKey = false, UserVerification = UserVerificationRequirement.Preferred, // AuthenticatorAttachment = null, }; AuthenticationExtensionsClientInputs clientExtensions = new AuthenticationExtensionsClientInputs { Extensions = true, SimpleTransactionAuthorization = string.Format("you are registering to {0}", fido2Config.ServerName), Location = true, UserVerificationMethod = true, }; var fido2 = new Fido2(fido2Config); var assertionRequest = Fido2NetLib.AssertionOptions.Create(fido2Config, challenge, allowedCredentials, UserVerificationRequirement.Preferred, clientExtensions); string assertionRequestJson = assertionRequest.ToJson(); return(assertionRequestJson); }
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()); }
public async Task <ActionResult> AssertionOptionsPost([FromForm] string username, [FromForm] string userVerification) { try { var identityUser = await _signInManager.GetTwoFactorAuthenticationUserAsync(); if (identityUser == null) { throw new InvalidOperationException($"Unable to load two-factor authentication user."); } var existingCredentials = new List <PublicKeyCredentialDescriptor>(); if (!string.IsNullOrEmpty(identityUser.UserName)) { var user = new Fido2User { DisplayName = identityUser.UserName, Name = identityUser.UserName, Id = Encoding.UTF8.GetBytes(identityUser.UserName) // byte representation of userID is required }; if (user == null) { throw new ArgumentException("Username was not registered"); } // 2. Get registered credentials from database var items = await _fido2Store.GetCredentialsByUserNameAsync(identityUser.UserName); existingCredentials = items.Select(c => c.Descriptor).NotNull().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 = _lib.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) })); } }
/// <summary> /// Returns CredentialCreateOptions including a challenge to be sent to the browser/authr to create new credentials /// </summary> /// <returns></returns> /// <param name="excludeCredentials">Recommended. This member is intended for use by Relying Parties that wish to limit the creation of multiple credentials for the same account on a single authenticator.The client is requested to return an error if the new credential would be created on an authenticator that also contains one of the credentials enumerated in this parameter.</param> public CredentialCreateOptions RequestNewCredential(Fido2User user, List <PublicKeyCredentialDescriptor> excludeCredentials, AuthenticationExtensionsClientInputs extensions = null) { return(RequestNewCredential(user, excludeCredentials, AuthenticatorSelection.Default, AttestationConveyancePreference.None, extensions)); }
internal static AssertionOptions Create(Fido2.Configuration config, byte[] challenge, IEnumerable <PublicKeyCredentialDescriptor> allowedCredentials, UserVerificationRequirement userVerification, AuthenticationExtensionsClientInputs extensions) { return(new AssertionOptions() { Status = "ok", ErrorMessage = string.Empty, Challenge = challenge, Timeout = config.Timeout, RpId = config.ServerDomain, AllowCredentials = allowedCredentials ?? new List <PublicKeyCredentialDescriptor>(), UserVerification = userVerification, Extensions = extensions }); }
public async Task <JsonResult> MakeCredentialOptions([FromForm] string username, [FromForm] string displayName, [FromForm] string attType, [FromForm] string authType, [FromForm] bool requireResidentKey, [FromForm] string userVerification) { try { if (string.IsNullOrEmpty(username)) { username = $"{displayName} (Usernameless user created at {DateTime.UtcNow})"; } var identityUser = await _userManager.FindByEmailAsync(username); var user = new Fido2User { DisplayName = identityUser.UserName, Name = identityUser.UserName, Id = Encoding.UTF8.GetBytes(identityUser.UserName) // byte representation of userID is required }; // 2. Get user existing keys by username var items = await _fido2Storage.GetCredentialsByUsername(identityUser.UserName); var existingKeys = new List <PublicKeyCredentialDescriptor>(); foreach (var publicKeyCredentialDescriptor in items) { existingKeys.Add(publicKeyCredentialDescriptor.Descriptor); } // 3. Create options var authenticatorSelection = new AuthenticatorSelection { RequireResidentKey = requireResidentKey, UserVerification = userVerification.ToEnum <UserVerificationRequirement>() }; if (!string.IsNullOrEmpty(authType)) { authenticatorSelection.AuthenticatorAttachment = authType.ToEnum <AuthenticatorAttachment>(); } var exts = new AuthenticationExtensionsClientInputs() { Extensions = true, UserVerificationIndex = true, Location = true, UserVerificationMethod = true, BiometricAuthenticatorPerformanceBounds = new AuthenticatorBiometricPerfBounds { FAR = float.MaxValue, FRR = float.MaxValue } }; var options = _lib.RequestNewCredential(user, existingKeys, authenticatorSelection, attType.ToEnum <AttestationConveyancePreference>(), exts); // 4. Temporarily store options, session/in-memory cache/redis/db //HttpContext.Session.SetString("fido2.attestationOptions", options.ToJson()); var uniqueId = Guid.NewGuid().ToString(); UniqueId = uniqueId; await _distributedCache.SetStringAsync(uniqueId, options.ToJson()); // 5. return options to client return(Json(options)); } catch (Exception e) { return(Json(new CredentialCreateOptions { Status = "error", ErrorMessage = FormatException(e) })); } }
/// <summary> /// Create static method implementation /// </summary> public static RegisterCredentialOptions Create(Fido2Configuration config, byte[] challenge, Fido2User user, AuthenticatorSelection authenticatorSelection, AttestationConveyancePreference attestationConveyancePreference, List <PublicKeyCredentialDescriptor> excludeCredentials, AuthenticationExtensionsClientInputs extensions) { return(new RegisterCredentialOptions { Status = "ok", ErrorMessage = string.Empty, Challenge = challenge, Rp = new PublicKeyCredentialRpEntity(config.ServerDomain, config.ServerName, config.ServerIcon), Timeout = config.Timeout, User = user, PubKeyCredParams = new List <PubKeyCredParam>() { // Add additional as appropriate ES256, RS256, PS256, ES384, RS384, PS384, ES512, RS512, PS512, }, AuthenticatorSelection = authenticatorSelection, Attestation = attestationConveyancePreference, ExcludeCredentials = excludeCredentials ?? new List <PublicKeyCredentialDescriptor>(), Extensions = extensions }); }