public async Task <Result <SignInResponse> > SignInAsync(string username, string password, Uri returnUrl)
        {
            if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(password))
            {
                return(Result.Failure <SignInResponse>(LoginUserErrors.UserNameOrPasswordIncorrect()));
            }

            var user = await _userManager.FindByNameAsync(username);

            if (user is null)
            {
                return(Result.Failure <SignInResponse>(LoginUserErrors.UserNameOrPasswordIncorrect()));
            }

            var context = await _interaction.GetAuthorizationContextAsync(returnUrl?.ToString());

            var isUserValidResult = await ValidateUserCredentialsAsync(user, password);

            if (!isUserValidResult.IsSuccess)
            {
                await _eventService.RaiseAsync(new UserLoginFailureEvent(user.UserName, ValidateUserMessage, clientId : context?.ClientId));

                return(Result.Failure <SignInResponse>(isUserValidResult.Errors));
            }

            var isUserDisabledResult = ValidateIfUserDisabled(user);

            if (!isUserDisabledResult.IsSuccess)
            {
                await _eventService.RaiseAsync(new UserLoginFailureEvent(user.UserName, DisabledEventMessage, clientId : context?.ClientId));

                return(Result.Failure <SignInResponse>(isUserDisabledResult.Errors));
            }

            var props = new AuthenticationProperties
            {
                RedirectUri  = context?.RedirectUri,
                AllowRefresh = true,
                IsPersistent = false
            };

            await _signInManager.SignInAsync(user, props);

            await RaiseLoginSuccessAsync(username, context);

            // We can trust returnUrl if GetAuthorizationContextAsync returned non-null
            return(Result.Success(new SignInResponse(context is object)));
        }
예제 #2
0
        public async Task <IActionResult> Login(LoginViewModel viewModel)
        {
            if (viewModel is null)
            {
                throw new ArgumentNullException(nameof(viewModel));
            }

            var returnUri = viewModel.ReturnUrl;

            if (returnUri is null)
            {
                return(RedirectToPublicBrowseLogin());
            }

            var signInResult = await loginService.SignInAsync(viewModel.EmailAddress, viewModel.Password, returnUri);

            LoginViewModel NewLoginViewModel() =>
            new()
            {
                ReturnUrl = viewModel.ReturnUrl, EmailAddress = signInResult.Value?.LoginHint
            };

            if (!ModelState.IsValid)
            {
                return(View(NewLoginViewModel()));
            }

            if (!signInResult.IsSuccess)
            {
                var signInErrors = signInResult.Errors;

                if (signInErrors.Contains(LoginUserErrors.UserNameOrPasswordIncorrect()))
                {
                    ModelState.Remove(nameof(LoginViewModel.Password));
                    ModelState.AddModelError(nameof(LoginViewModel.EmailAddress), SignInErrorMessage);
                    ModelState.AddModelError(nameof(LoginViewModel.Password), SignInErrorMessage);
                }

                if (!signInErrors.Contains(LoginUserErrors.UserIsDisabled()))
                {
                    return(View(NewLoginViewModel()));
                }

                var disabledErrorFormat = string.Format(
                    CultureInfo.CurrentCulture,
                    UserDisabledErrorMessageTemplate,
                    disabledErrorMessageSettings.EmailAddress,
                    disabledErrorMessageSettings.PhoneNumber);

                ModelState.AddModelError(nameof(LoginViewModel.DisabledError), disabledErrorFormat);

                return(View(NewLoginViewModel()));
            }

            var returnUrl = returnUri.ToString();

            // We can trust viewModel.ReturnUrl since GetAuthorizationContextAsync returned non-null
            if (signInResult.Value.IsTrustedReturnUrl)
            {
                return(Redirect(returnUrl));
            }

            return(LocalRedirect(returnUrl));
        }
        private async Task <Result> ValidateUserCredentialsAsync(ApplicationUser user, string password)
        {
            var result = await _signInManager.CheckPasswordSignInAsync(user, password, true);

            return(result.Succeeded ? Result.Success() : Result.Failure(LoginUserErrors.UserNameOrPasswordIncorrect()));
        }
 private static Result ValidateIfUserDisabled(ApplicationUser user)
 {
     return(!user.Disabled ? Result.Success() : Result.Failure(LoginUserErrors.UserIsDisabled()));
 }
예제 #5
0
        public async Task Login_LoginViewModel_FailedSignIn_AddsDisabledValidationError()
        {
            const string email       = "*****@*****.**";
            const string phoneNumber = "012345678901";

            var disabledSetting = new DisabledErrorMessageSettings()
            {
                EmailAddress = email,
                PhoneNumber  = phoneNumber
            };

            using var controller = AccountControllerBuilder
                                   .Create()
                                   .WithSignInResult(Result.Failure <SignInResponse>(new List <ErrorDetails> { LoginUserErrors.UserIsDisabled() }))
                                   .WithDisabledErrorMessageSetting(disabledSetting)
                                   .Build();

            await controller.Login(LoginViewModelBuilder.Create().Build());

            var modelState = controller.ModelState;

            modelState.IsValid.Should().BeFalse();
            modelState.Count.Should().Be(1);

            (string key, ModelStateEntry entry) = modelState.First();
            key.Should().Be(nameof(LoginViewModel.DisabledError));
            entry.Errors.Count.Should().Be(1);
            var expected = string.Format(CultureInfo.CurrentCulture, AccountController.UserDisabledErrorMessageTemplate, email,
                                         phoneNumber);

            entry.Errors.First().ErrorMessage.Should().Be(expected);
        }
예제 #6
0
        public async Task Login_LoginViewModel_FailedSignIn_AddsUsernameOrPasswordValidationError()
        {
            using var controller = AccountControllerBuilder
                                   .Create()
                                   .WithSignInResult(Result.Failure <SignInResponse>(new List <ErrorDetails> { LoginUserErrors.UserNameOrPasswordIncorrect() }))
                                   .Build();

            await controller.Login(LoginViewModelBuilder.Create().Build());

            var modelState = controller.ModelState;

            modelState.IsValid.Should().BeFalse();
            modelState.Count.Should().Be(2);

            foreach ((string key, ModelStateEntry entry) in modelState)
            {
                entry.Errors.Count.Should().Be(1);
                entry.Errors.First().ErrorMessage.Should().Be(AccountController.SignInErrorMessage);
            }
        }