Пример #1
0
        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
                }));
            }
        }
Пример #2
0
        /// <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);
        }
Пример #3
0
        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);
            }
        }
Пример #4
0
        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"));
            }
        }
Пример #7
0
        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)
                }));
            }
        }
Пример #8
0
        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);
        }
Пример #9
0
        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());
        }