public async Task <ActionResult <UserDetail> > PostLogin(LoginModel loginModel) { // Sign the user in with username/password, this also gives a chance for developers to // custom verify the credentials and auto-link user accounts with a custom IBackOfficePasswordChecker SignInResult result = await _signInManager.PasswordSignInAsync( loginModel.Username, loginModel.Password, isPersistent : true, lockoutOnFailure : true); if (result.Succeeded) { // return the user detail return(GetUserDetail(_userService.GetByUsername(loginModel.Username))); } if (result.RequiresTwoFactor) { var twofactorView = _backOfficeTwoFactorOptions.GetTwoFactorView(loginModel.Username); if (twofactorView.IsNullOrWhiteSpace()) { return(new ValidationErrorResult($"The registered {typeof(IBackOfficeTwoFactorOptions)} of type {_backOfficeTwoFactorOptions.GetType()} did not return a view for two factor auth ")); } IUser attemptedUser = _userService.GetByUsername(loginModel.Username); // create a with information to display a custom two factor send code view var verifyResponse = new ObjectResult(new { twoFactorView = twofactorView, userId = attemptedUser.Id }) { StatusCode = StatusCodes.Status402PaymentRequired }; return(verifyResponse); } // TODO: We can check for these and respond differently if we think it's important // result.IsLockedOut // result.IsNotAllowed // return BadRequest (400), we don't want to return a 401 because that get's intercepted // by our angular helper because it thinks that we need to re-perform the request once we are // authorized and we don't want to return a 403 because angular will show a warning message indicating // that the user doesn't have access to perform this function, we just want to return a normal invalid message. return(BadRequest()); }
private async Task <IActionResult> ExternalSignInAsync(ExternalLoginInfo loginInfo, Func <IActionResult> response) { if (loginInfo == null) { throw new ArgumentNullException(nameof(loginInfo)); } if (response == null) { throw new ArgumentNullException(nameof(response)); } // Sign in the user with this external login provider (which auto links, etc...) SignInResult result = await _signInManager.ExternalLoginSignInAsync(loginInfo, isPersistent : false); var errors = new List <string>(); if (result == SignInResult.Success) { // Update any authentication tokens if succeeded await _signInManager.UpdateExternalAuthenticationTokensAsync(loginInfo); // Check if we are in an upgrade state, if so we need to redirect if (_runtimeState.Level == Core.RuntimeLevel.Upgrade) { // redirect to the the installer return(Redirect("/")); } } else if (result == SignInResult.TwoFactorRequired) { var attemptedUser = await _userManager.FindByLoginAsync(loginInfo.LoginProvider, loginInfo.ProviderKey); if (attemptedUser == null) { return(new ValidationErrorResult($"No local user found for the login provider {loginInfo.LoginProvider} - {loginInfo.ProviderKey}")); } var twofactorView = _backOfficeTwoFactorOptions.GetTwoFactorView(attemptedUser.UserName); if (twofactorView.IsNullOrWhiteSpace()) { return(new ValidationErrorResult($"The registered {typeof(IBackOfficeTwoFactorOptions)} of type {_backOfficeTwoFactorOptions.GetType()} did not return a view for two factor auth ")); } // create a with information to display a custom two factor send code view var verifyResponse = new ObjectResult(new { twoFactorView = twofactorView, userId = attemptedUser.Id }) { StatusCode = StatusCodes.Status402PaymentRequired }; return(verifyResponse); } else if (result == SignInResult.LockedOut) { errors.Add($"The local user {loginInfo.Principal.Identity.Name} for the external provider {loginInfo.ProviderDisplayName} is locked out."); } else if (result == SignInResult.NotAllowed) { // This occurs when SignInManager.CanSignInAsync fails which is when RequireConfirmedEmail , RequireConfirmedPhoneNumber or RequireConfirmedAccount fails // however since we don't enforce those rules (yet) this shouldn't happen. errors.Add($"The user {loginInfo.Principal.Identity.Name} for the external provider {loginInfo.ProviderDisplayName} has not confirmed their details and cannot sign in."); } else if (result == SignInResult.Failed) { // Failed only occurs when the user does not exist errors.Add("The requested provider (" + loginInfo.LoginProvider + ") has not been linked to an account, the provider must be linked from the back office."); } else if (result == AutoLinkSignInResult.FailedNotLinked) { errors.Add("The requested provider (" + loginInfo.LoginProvider + ") has not been linked to an account, the provider must be linked from the back office."); } else if (result == AutoLinkSignInResult.FailedNoEmail) { errors.Add($"The requested provider ({loginInfo.LoginProvider}) has not provided the email claim {ClaimTypes.Email}, the account cannot be linked."); } else if (result is AutoLinkSignInResult autoLinkSignInResult && autoLinkSignInResult.Errors.Count > 0) { errors.AddRange(autoLinkSignInResult.Errors); }