///<inheritdoc/>
        public async Task <IdentityResult> ValidateAsync(
            UserManager <TUser> manager,
            TUser user,
            string password)
        {
            var(pwned, count) = await _passwordService.IsPasswordPwnedAsync(password);

            if (pwned)
            {
                return(await Task.FromResult(IdentityResult.Failed(new IdentityError
                {
                    Code = "PwnedPassword",
                    Description = $"The password you chose has appeared in a data breach {count} times. It is recommended that you change your password immediately"
                })).ConfigureAwait(false));
            }
            return(await Task.FromResult(IdentityResult.Success).ConfigureAwait(false));
        }
예제 #2
0
        public async Task <IActionResult> OnPostAsync(string returnUrl = null)
        {
            returnUrl = returnUrl ?? Url.Content("~/");

            if (ModelState.IsValid)
            {
                var(pwned, count) = await _passwordService.IsPasswordPwnedAsync(Input.Password);

                // This doesn't count login failures towards account lockout
                // To enable password failures to trigger account lockout, set lockoutOnFailure: true
                var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure : true);

                if (result.Succeeded)
                {
                    _logger.LogInformation("User logged in.");

                    if (pwned)
                    {
                        _logger.LogInformation("User's password has been pwned");
                        return(RedirectToPage("./PwnedPassword", new { ReturnUrl = returnUrl, Count = count }));
                    }

                    return(LocalRedirect(returnUrl));
                }
                if (result.RequiresTwoFactor)
                {
                    return(RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, Input.RememberMe }));
                }
                if (result.IsLockedOut)
                {
                    _logger.LogWarning("User account locked out.");
                    return(RedirectToPage("./Lockout"));
                }
                else
                {
                    ModelState.AddModelError(string.Empty, "Invalid login attempt.");
                    return(Page());
                }
            }

            // If we got this far, something failed, redisplay form
            return(Page());
        }
예제 #3
0
        public async Task <IActionResult> Register([BindRequired, FromBody, FromForm] RegisterModel model)
        {
            var(pwned, count) = await pwnedPasswordService.IsPasswordPwnedAsync(model.Password).ConfigureAwait(false);

            if (pwned)
            {
                return(Ok(new RegisterResults
                {
                    IsPwned = true,
                    ErrorMessage = string.Format(PwnedPasswordMessage, count),
                }));
            }

            // See if we're already registered.
            var emailLower   = model.Email.ToLowerInvariant();
            var existingUser = await userManager.FindByEmailAsync(emailLower).ConfigureAwait(false);

            if (existingUser != null)
            {
                return(Ok(new RegisterResults
                {
                    ErrorMessage = "You're already registered.",
                    IsAlreadyRegistered = true,
                    NeedsConfirmation = !existingUser.EmailConfirmed
                }));
            }

            // Reject throwaway emails. We need to do this because this helps prevent upvote/downvote fraud.
            var throwawayDomainsDoc = await DbSession.LoadOptionalAsync <ThrowawayEmailDomains>("ThrowawayEmailDomains/1");

            var attemptedDomain  = emailLower.Substring(emailLower.LastIndexOf('@') + 1);
            var isThrowawayEmail = throwawayDomainsDoc?.Domains.Contains(attemptedDomain, StringComparison.InvariantCultureIgnoreCase);

            if (isThrowawayEmail == true)
            {
                logger.LogInformation("Rejected attempt to register with a throwaway email address {email}", emailLower);
                return(Ok(new RegisterResults
                {
                    ErrorMessage = "Throwaway email accounts are unable to register with Chavah. Please use a valid email address. We'll never send spam nor share your email with anyone."
                }));
            }

            // The user doesn't exist yet. Try and register him.
            var user = new AppUser
            {
                Id               = $"AppUsers/{emailLower}",
                UserName         = model.Email,
                Email            = model.Email,
                LastSeen         = DateTime.UtcNow,
                RegistrationDate = DateTime.UtcNow
            };
            var createUserResult = await userManager.CreateAsync(user, model.Password).ConfigureAwait(false);

            if (createUserResult.Succeeded)
            {
                // Send confirmation email.
                var confirmToken = new AccountToken //await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
                {
                    Id = $"AccountTokens/Confirm/{emailLower}",
                    ApplicationUserId = user.Id,
                    Token             = Guid.NewGuid().ToString()
                };
                await DbSession.StoreAsync(confirmToken);

                DbSession.SetRavenExpiration(confirmToken, DateTime.UtcNow.AddDays(14));

                emailSender.QueueConfirmEmail(model.Email, confirmToken.Token, appOptions);

                logger.LogInformation("Sending new user confirmation email to {email} with confirm token {token}", model.Email, confirmToken.Token);
                return(Ok(new RegisterResults
                {
                    Success = true
                }));
            }
            else
            {
                // Registration failed.
                logger.LogWarning("Register new user failed with {result}", createUserResult);
                return(Ok(new RegisterResults
                {
                    ErrorMessage = string.Join(", ", createUserResult.Errors.Select(s => s.Description))
                }));
            }
        }