public async Task <LoginResponse> MakeAssertion([FromBody][Required] MakeAssertionRequest request)
        {
            using (AuthLogic.Disable())
                using (Transaction tr = new Transaction())
                {
                    var assertionOptions = Database.Retrieve <WebAuthnAssertionOptionsEntity>(request.AssertionOptionsId);
                    var options          = AssertionOptions.FromJson(assertionOptions.Json);

                    var cred = Database.Query <WebAuthnCredentialEntity>().SingleEx(cred => cred.CredentialId == request.AssertionRawResponse.Id);

                    var res = await fido2.MakeAssertionAsync(request.AssertionRawResponse, options, cred.PublicKey, (uint)cred.Counter, (args) =>
                    {
                        if (!MemoryExtensions.SequenceEqual <byte>(cred.CredentialId, args.CredentialId))
                        {
                            return(Task.FromResult(false));
                        }

                        var userId = Encoding.UTF8.GetBytes(cred.User.Id.ToString());
                        if (!MemoryExtensions.SequenceEqual <byte>(userId, args.UserHandle))
                        {
                            return(Task.FromResult(false));
                        }

                        return(Task.FromResult(true));
                    });

                    cred.Counter++;
                    cred.Save();

                    var user = cred.User.RetrieveAndForget();

                    AuthServer.OnUserPreLogin(ControllerContext, user);

                    AuthServer.AddUserSession(ControllerContext, user);

                    var token = AuthTokenServer.CreateToken(user);

                    return(tr.Commit(new LoginResponse {
                        userEntity = user, token = token, authenticationType = "webauthn"
                    }));
                }
        }
示例#2
0
        public async Task <ActionResult> MakeAssertion([ModelBinder(typeof(NewtonsoftJsonAdapter.Binder))] MakeAssertionRequest request)
        {
            try
            {
                // 1. Get the assertion options we sent the client
                var jsonOptions = TestUsers.FidoAttestationOptions[request.SessionId];
                var options     = AssertionOptions.FromJson(jsonOptions);

                // 2. Get registered credential from database
                var creds = TestUsers.FidoCredentials.Where(c => c.Descriptor.Id.SequenceEqual(request.RawResponse.Id)).FirstOrDefault();
                if (creds == null)
                {
                    return(BadRequest("unknown credentials"));
                }

                // 3. Get credential counter from database
                var storedCounter = creds.SignatureCounter;

                // 4. Create callback to check if userhandle owns the credentialId
                IsUserHandleOwnerOfCredentialIdAsync callback = async(args) =>
                {
                    var storedCreds = TestUsers.FidoCredentials.Where(c => c.UserHandle.SequenceEqual(args.UserHandle));
                    return(storedCreds.Any(c => c.Descriptor.Id.SequenceEqual(args.CredentialId)));
                };

                // 5. Make the assertion
                var res = await _lib.MakeAssertionAsync(
                    assertionResponse : request.RawResponse,
                    originalOptions : options,
                    storedPublicKey : creds.PublicKey,
                    storedSignatureCounter : storedCounter,
                    isUserHandleOwnerOfCredentialIdCallback : callback);

                // 6. Store the updated counter
                TestUsers.FidoCredentials.Where(c => c.Descriptor.Id.SequenceEqual(res.CredentialId)).FirstOrDefault().SignatureCounter = res.Counter;

                // 7. return OK to client
                if (string.Equals(res.Status, "ok", StringComparison.InvariantCultureIgnoreCase))
                {
                    //actually loging the user in
                    var context = await _interaction.GetAuthorizationContextAsync(request.ReturnUrl);

                    var dbUser = TestUsers.Users.FirstOrDefault(u => string.Equals(u.SubjectId, creds.SubjectId, StringComparison.InvariantCultureIgnoreCase));
                    AuthenticationProperties props = null;
                    if (AccountOptions.AllowRememberLogin && request.RememberLogin)
                    {
                        props = new AuthenticationProperties
                        {
                            IsPersistent = true,
                            ExpiresUtc   = DateTimeOffset.UtcNow.Add(AccountOptions.RememberMeLoginDuration)
                        };
                    }
                    ;
                    var isuser = new IdentityServerUser(dbUser.SubjectId)
                    {
                        DisplayName = dbUser.Username
                    };
                    await HttpContext.SignInAsync(isuser, props);

                    if (context != null)
                    {
                        // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                        return(this.NewtonsoftJsonResult(new MakeAssertionResponse {
                            Status = "ok", Response = res, ReturnUrl = request.ReturnUrl
                        }));
                    }

                    // request for a local page
                    if (Url.IsLocalUrl(request.ReturnUrl))
                    {
                        return(this.NewtonsoftJsonResult(new MakeAssertionResponse {
                            Status = "ok", Response = res, ReturnUrl = request.ReturnUrl
                        }));
                    }
                    else if (string.IsNullOrEmpty(request.ReturnUrl))
                    {
                        return(this.NewtonsoftJsonResult(new MakeAssertionResponse {
                            Status = "ok", Response = res, ReturnUrl = "~/"
                        }));
                    }
                    else
                    {
                        // user might have clicked on a malicious link - should be logged
                        throw new Exception("invalid return URL");
                    }
                }
                else
                {
                    return(BadRequest("not ok"));
                }
            }
            catch (Exception e)
            {
                return(BadRequest(new AssertionVerificationResult {
                    Status = "error", ErrorMessage = FormatException(e)
                }));
            }
        }