コード例 #1
0
        public async Task <IActionResult> Validate(TwoFactorValidateModel model)
        {
            if (ModelState.IsValid)
            {
                var email = model.Email.Clean();
                if (string.IsNullOrEmpty(email))
                {
                    return(Unauthorized());
                }

                var user = await _userManager.FindByEmailAsync(email);

                if (user == null)
                {
                    return(Unauthorized());
                }

                var totpCode       = model.TotpCode?.Replace(" ", string.Empty).Replace("-", string.Empty) ?? string.Empty;
                var twoFactorToken = user.Tokens.Where(x => x.LoginProvider == "Two-Factor").Select(x => x.Value).FirstOrDefault();
                if (string.IsNullOrEmpty(twoFactorToken))
                {
                    return(Unauthorized());
                }

                var totp        = new Totp(Base32Encoding.ToBytes(twoFactorToken));
                var computeTotp = totp.ComputeTotp(DateTime.UtcNow);

                if (totpCode.Equals(computeTotp))
                {
                    var additionalLocalClaims = new List <Claim>();
                    var localSignInProps      = new AuthenticationProperties();
                    if (model.AuthenticationToken != null)
                    {
                        localSignInProps.StoreTokens(new[] { new AuthenticationToken {
                                                                 Name = "id_token", Value = model.AuthenticationToken
                                                             } });
                    }

                    // issue authentication cookie for user
                    // we must issue the cookie maually, and can't use the SignInManager because
                    // it doesn't expose an API to issue additional claims from the login workflow
                    var principal = await _signInManager.CreateUserPrincipalAsync(user);

                    additionalLocalClaims.AddRange(principal.Claims);
                    var name = user.FullName; //principal.FindFirst(JwtClaimTypes.Name)?.Value ?? user.Id;

                    var isuser = new IdentityServerUser(user.Id)
                    {
                        DisplayName      = name,
                        IdentityProvider = model.Provider,
                        AdditionalClaims = additionalLocalClaims
                    };

                    await HttpContext.SignInAsync(isuser, localSignInProps);

                    // delete temporary cookie used during external authentication
                    await HttpContext.SignOutAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);

                    // retrieve return URL
                    var returnUrl = model.ReturnUrl ?? _appSettings.Application.MainSiteUrlTrim + "/Home/Index";

                    // check if external login is in the context of an OIDC request
                    var context = await _interaction.GetAuthorizationContextAsync(returnUrl);

                    await _events.RaiseAsync(new UserLoginSuccessEvent(model.Provider, model.ProviderUserId, user.Id, name, true, context?.Client.ClientId));

                    if (context != null)
                    {
                        if (context.IsNativeClient())
                        {
                            // The client is native, so this change in how to
                            // return the response is for better UX for the end user.
                            return(this.LoadingPage("Redirect", returnUrl));
                        }
                    }

                    return(Redirect(returnUrl));
                }

                return(Unauthorized());
            }

            return(View(model));
        }
コード例 #2
0
        public async Task <IActionResult> Callback()
        {
            // read external identity from the temporary cookie
            var result = await HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);

            if (result?.Succeeded != true)
            {
                _logger.Exception(result.Failure);
                string errMsg = "External authentication error - " + result.Failure.Message;
                errMsg += (result.Failure.InnerException != null) ? (" - " + result.Failure.InnerException.Message) : string.Empty;

                throw new HttpRequestException(
                          CDCavell.ClassLibrary.Web.Html.StatusCodes.ToString(401),
                          new Exception(errMsg),
                          HttpStatusCode.Unauthorized
                          );
            }

            if (_logger.IsEnabled(LogLevel.Debug))
            {
                var externalClaims = result.Principal.Claims.Select(c => $"{c.Type}: {c.Value}");
                _logger.Debug($"External claims: {externalClaims}");
            }

            // lookup our user and external provider info
            var(user, provider, providerUserId, claims) = await FindUserFromExternalProviderAsync(result);

            if (user == null)
            {
                // this might be where you might initiate a custom workflow for user registration
                // in this sample we don't show how that would be done, as our sample implementation
                // simply auto-provisions new external user
                user = await AutoProvisionUserAsync(provider, providerUserId, claims);
            }

            // validate email address
            if (!user.EmailConfirmed)
            {
                // delete temporary cookie used during external authentication
                await HttpContext.SignOutAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);

                TempData["Email"] = user.Email;
                return(RedirectToAction("Index", "Registration"));
            }

            if (user.TwoFactorEnabled)
            {
                TwoFactorValidateModel model = new TwoFactorValidateModel();
                model.Email          = user.Email;
                model.Provider       = provider;
                model.ProviderUserId = providerUserId;
                model.ReturnUrl      = result.Properties.Items["returnUrl"];

                // if the external system sent a session id claim, copy it over
                // so we can use it for single sign-out
                var sid = result.Principal.Claims.FirstOrDefault(x => x.Type == JwtClaimTypes.SessionId);
                if (sid != null)
                {
                    model.SessionId = sid.Value;
                }

                // if the external provider issued an id_token, we'll keep it for signout
                var idToken = result.Properties.GetTokenValue("id_token");
                if (idToken != null)
                {
                    model.AuthenticationToken = idToken;
                }

                TempData["TwoFactorValidateModel"] = JsonConvert.SerializeObject(model);
                return(RedirectToAction("Validate", "TwoFactor"));
            }

            // this allows us to collect any additional claims or properties
            // for the specific protocols used and store them in the local auth cookie.
            // this is typically used to store data needed for signout from those protocols.
            var additionalLocalClaims = new List <Claim>();
            var localSignInProps      = new AuthenticationProperties();

            ProcessLoginCallback(result, additionalLocalClaims, localSignInProps);

            // issue authentication cookie for user
            // we must issue the cookie maually, and can't use the SignInManager because
            // it doesn't expose an API to issue additional claims from the login workflow
            var principal = await _signInManager.CreateUserPrincipalAsync(user);

            additionalLocalClaims.AddRange(principal.Claims);
            var name = user.FullName; //principal.FindFirst(JwtClaimTypes.Name)?.Value ?? user.Id;

            var isuser = new IdentityServerUser(user.Id)
            {
                DisplayName      = name,
                IdentityProvider = provider,
                AdditionalClaims = additionalLocalClaims
            };

            await HttpContext.SignInAsync(isuser, localSignInProps);

            // delete temporary cookie used during external authentication
            await HttpContext.SignOutAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);

            // retrieve return URL
            var returnUrl = result.Properties.Items["returnUrl"] ?? "~/";

            // check if external login is in the context of an OIDC request
            var context = await _interaction.GetAuthorizationContextAsync(returnUrl);

            await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.Id, name, true, context?.Client.ClientId));

            if (context != null)
            {
                if (context.IsNativeClient())
                {
                    // The client is native, so this change in how to
                    // return the response is for better UX for the end user.
                    return(this.LoadingPage("Redirect", returnUrl));
                }
            }

            return(Redirect(returnUrl));
        }