Quantcast
Channel: ASP.NET Core
Viewing all articles
Browse latest Browse all 9386

SignInManager.GetExternalLoginInfoAsync returns null

$
0
0

SignInManager<ApplicationUser>.GetExternalLoginInfoAsync returns null. I am not sure why. I am trying to retrieve the same"userId" (user-defined) that I stored in the cache via "OnAuthorizationCodeReceived":

        public async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext context)
        {
            //  string userId = context.Ticket.Principal.FindFirst(ClaimTypes.NameIdentifier).Value;
            //  string userId = context.HttpContext.User.Identity.Name;
            string userId = context.Principal.
                FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
            // Use MSAL to swap the code for an access token
            // Extract the code from the response notification
            string code = context.ProtocolMessage.Code;

            TokenCache tokenCache = new SessionTokenCache(userId, context.HttpContext).GetMsalCacheInstance();
            ClientCredential clientCred = new ClientCredential(azureadclientsecret);
            ConfidentialClientApplication cca = new ConfidentialClientApplication(azureadclientid,
                string.Format(CultureInfo.InvariantCulture, azureadaadinstance, "common", "/v2.0"),
                oauth2redirecturi,
                clientCred,
                tokenCache,
                null);

            try
            {
                AuthenticationResult result = await cca.AcquireTokenByAuthorizationCodeAsync(code, oauth2appscopes.Split(' '));
                context.HandleCodeRedemption(result.AccessToken, result.IdToken);
            }
            catch
            {
                AuthenticationResult result = await cca.AcquireTokenSilentAsync(oauth2appscopes.Split(' '), cca.Users.First());
                //  throw;
            }
        }

In the following task where the app gets the access token, SignInManager<ApplicationUser>.GetExternalLoginInfoAsync returns null (need to get the "ExternalLoginInfo", so that I can get the "userId" (user-defined) from it):

        public async Task<string> GetAccessToken()
        {
            string accessToken = null;

            // Load the app config from web.config
            string appId = _oauth2.AppId;
            string appPassword = _oauth2.AppPassword;
            string redirectUri = _oauth2.RedirectUri;
            string[] appScopes = _oauth2.AppScopes
                .Replace(' ', ',').Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

            ExternalLoginInfo info = await _signInManager.GetExternalLoginInfoAsync(/*userId*/);

            //  ClaimsPrincipal principal = User as ClaimsPrincipal;
            //  ClaimsIdentity principalIdentity = principal.Identity as ClaimsIdentity;

            string userId = info.Principal.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;

            //  Get the current user's ID
            //  string userId = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
            //  string userId = principalIdentity.FindFirst(ClaimTypes.NameIdentifier).Value;
            //  string userId = principal.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;

            if (!string.IsNullOrEmpty(userId))
            {
                // Get the user's token cache
                Microsoft.Identity.Client.TokenCache tokenCache = new SessionTokenCache(userId, HttpContext).GetMsalCacheInstance();
                //  Microsoft.Identity.Client.TokenCache tokenCache = new NaiveSessionCache(userId, HttpContext.Session);

                ConfidentialClientApplication cca = new ConfidentialClientApplication(
                    appId, redirectUri, new Microsoft.Identity.Client.ClientCredential(appPassword), tokenCache, null);

                Microsoft.Identity.Client.AuthenticationResult result = await cca.AcquireTokenSilentAsync(appScopes, cca.Users.First());
                if (result != null)
                {
                    accessToken = result.AccessToken;
                }
            }

            return accessToken;
        }

After logging into an account with an external login, I tried accessing the inbox of the external login, but it is not working, ultimately because of SignInManager<ApplicationUser>.GetExternalLoginInfoAsync returning null. I do not know how I can get the "userId" (user-defined) another way.

It appears that the only times that SignInManager<ApplicationUser>.GetExternalLoginInfoAsync DOES NOT return null is in the following two functions, which are callback functions that execute after a user logs in via an external login provider:

        //
        // GET: /Manage/LinkLoginCallback
        [HttpGet]
        public async Task<ActionResult> LinkLoginCallback()
        {
            try
            {
                var user = await GetCurrentUserAsync();
                if (user == null)
                {
                    return View("Error");
                }
                var info = await _signInManager.GetExternalLoginInfoAsync(/*_userManager.GetUserId(User)*/);
                if (info.LoginProvider == "" || info.Principal.FindFirst("preferred_username").Value == "")
                {
                    return RedirectToAction(nameof(ManageLogins), new { Message = ManageMessageId.EmptyError });
                }
                var result = await _userManager.AddLoginAsync(user, info);
                var message = ManageMessageId.Error;
                if (result.Succeeded)
                {
                    var code = await _userManager.GeneratePasswordResetTokenAsync(user);
                    var callbackUrl = Url.Action("ResetPassword", "Account", new
                    {
                        userId = user.Id,
                        code = code
                    }, protocol: HttpContext.Request.Scheme);

                    string emailSubjectToVisitor = "A(n) " + info.LoginProvider + " account (UserName: " +
                        info.Principal.FindFirst("preferred_username").Value + ") has been added to your " +"globalwarming.center account (UserName: " + user.UserName + ")";
                    string emailMessageToVisitor = "<p>Dear " + user.UserName + ":</p><p>" +"A(n) " + info.LoginProvider + " account (UserName: " +
                        info.Principal.FindFirst("preferred_username").Value + ") has been added to your " +"globalwarming.center account (UserName: " + user.UserName + ").</p><p>If you did " +"not add this account, someone else may have access to your globalwarming.center " +"account. You should immediately reset your password by clicking this " +$"<a href='{callbackUrl}'>link</a> and filling out the form. That way, you can " +"change your password and prevent anyone else from logging into your " +"account. Then, you should log into your account and remove the " +
                        info.LoginProvider + " account, if necessary.</p><p>" +"Thank you." + "</p><p>" +"Sincerely," + "<br>" +
                        _pointOfContact.FullName + "<br>" +
                        _pointOfContact.Title + "</p>";
                    await _emailSender.SendEmailAsync(user.Email, emailSubjectToVisitor,
                        emailMessageToVisitor);

                    message = ManageMessageId.AddLoginSuccess;
                    // Clear the existing external cookie to ensure a clean login process
                    await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);

                    return RedirectToAction(nameof(ManageLogins), new {
                        Message = ManageMessageId.AddLoginSuccess
                    });
                }
                else
                {
                    string error = result.Errors.First().Description;
                    return RedirectToAction(nameof(ManageLogins), new {
                        Message = message,
                        Error = error
                    });
                }
            }
            catch (Exception ex)
            {
                return RedirectToAction(nameof(ManageLogins), new { Message = ManageMessageId.Error, Error = ex.Message });
            }
        }
        //
        // GET: /Account/ExternalLoginCallback
        [HttpGet]
        [AllowAnonymous]
        public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
        {
            if (remoteError != null)
            {
                ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}");
                return View(nameof(Login));
            }
            ExternalLoginInfo info = await _signInManager.GetExternalLoginInfoAsync(/*_userManager.GetUserId(User)*/);
            if (info == null)
            {
                //  return RedirectToAction(nameof(Login));
                ModelState.AddModelError(string.Empty, "Could not get external login info");
                return View(nameof(Login));
            }

            // Sign in the user with this external login provider if the user already has a login.
            var result = await _signInManager.ExternalLoginSignInAsync(
                info.LoginProvider,
                info.ProviderKey,
                isPersistent: false);
            if (result.Succeeded)
            {
                _logger.LogInformation(5, "User logged in with {Name} provider.", info.LoginProvider);
                return RedirectToLocal(returnUrl);
            }
            /*
            if (result.RequiresTwoFactor)
            {
                return RedirectToAction(nameof(SendCode), new { ReturnUrl = returnUrl });
            }
            */
            if (result.IsLockedOut)
            {
                return View("Lockout");
            }
            else
            {
                // If the user does not have an account, then ask the user to create an account.
                ViewData["ReturnUrl"] = returnUrl;
                ViewData["LoginProvider"] = info.LoginProvider;
                ClaimsIdentity principalIdentity = info.Principal.Identity as ClaimsIdentity;
                string preferredUsername = principalIdentity.FindFirst("preferred_username").Value;
                ViewData["PreferredUsername"] = preferredUsername;
                return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel {
                    Email = preferredUsername
                });
            }
        }

Here is the link to my GitHub repository.

Thank you.


Viewing all articles
Browse latest Browse all 9386

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>