private IHttpActionResult SignInAndRedirect(SignInMessage signInMessage, string signInMessageId, AuthenticateResult authResult, bool?rememberMe = null)
        {
            IssueAuthenticationCookie(signInMessage, signInMessageId, authResult, rememberMe);

            var redirectUrl = GetRedirectUrl(signInMessage, authResult);

            Logger.InfoFormat("redirecting to: {0}", redirectUrl);
            return(Redirect(redirectUrl));
        }
        private void IssueAuthenticationCookie(SignInMessage signInMessage, string signInMessageId, AuthenticateResult authResult, bool?rememberMe = null)
        {
            if (signInMessage == null)
            {
                throw new ArgumentNullException("signInId");
            }
            if (authResult == null)
            {
                throw new ArgumentNullException("authResult");
            }

            Logger.InfoFormat("issuing cookie{0}", authResult.IsPartialSignIn ? " (partial login)" : "");

            var props = new Microsoft.Owin.Security.AuthenticationProperties();

            var id = authResult.User.Identities.First();

            if (authResult.IsPartialSignIn)
            {
                // add claim so partial redirect can return here to continue login
                // we need a random ID to resume, and this will be the query string
                // to match a claim added. the claim added will be the original
                // signIn ID.
                var resumeId = Guid.NewGuid().ToString("N");

                var resumeLoginUrl   = Url.Link(Constants.RouteNames.ResumeLoginFromRedirect, new { resume = resumeId });
                var resumeLoginClaim = new Claim(Constants.ClaimTypes.PartialLoginReturnUrl, resumeLoginUrl);
                id.AddClaim(resumeLoginClaim);
                id.AddClaim(new Claim(GetClaimTypeForResumeId(resumeId), signInMessageId));
            }
            else
            {
                ClearSignInCookie(signInMessageId);
            }

            if (!authResult.IsPartialSignIn)
            {
                // don't issue persistnt cookie if it's a partial signin
                if (rememberMe == true ||
                    (rememberMe != false && this._options.AuthenticationOptions.CookieOptions.IsPersistent))
                {
                    // only issue persistent cookie if user consents (rememberMe == true) or
                    // if server is configured to issue persistent cookies and user has not explicitly
                    // denied the rememberMe (false)
                    // if rememberMe is null, then user was not prompted for rememberMe
                    props.IsPersistent = true;
                    if (rememberMe == true)
                    {
                        var expires = DateTime.UtcNow.Add(_options.AuthenticationOptions.CookieOptions.RememberMeDuration);
                        props.ExpiresUtc = new DateTimeOffset(expires);
                    }
                }
            }

            ClearAuthenticationCookies();

            var ctx = Request.GetOwinContext();

            ctx.Authentication.SignIn(props, id);
        }
        public async Task <IHttpActionResult> ResumeLoginFromRedirect(string resume)
        {
            Logger.Info("Callback requested to resume login from partial login");

            if (resume.IsMissing())
            {
                Logger.Error("no resumeId passed");
                return(RenderErrorPage());
            }

            var user = await GetIdentityFromPartialSignIn();

            if (user == null)
            {
                Logger.Error("no identity from partial login");
                return(RenderErrorPage());
            }

            var type        = GetClaimTypeForResumeId(resume);
            var resumeClaim = user.FindFirst(type);

            if (resumeClaim == null)
            {
                Logger.Error("no claim matching resumeId");
                return(RenderErrorPage());
            }

            var signInId = resumeClaim.Value;

            if (signInId.IsMissing())
            {
                Logger.Error("No signin id found in resume claim");
                return(RenderErrorPage());
            }

            var cookie        = new MessageCookie <SignInMessage>(Request.GetOwinContext(), this._options);
            var signInMessage = cookie.Read(signInId);

            if (signInMessage == null)
            {
                Logger.Error("No cookie matching signin id found");
                return(RenderErrorPage());
            }

            AuthenticateResult result = null;
            var externalProviderClaim = user.FindFirst(Constants.ClaimTypes.ExternalProviderUserId);

            if (externalProviderClaim == null)
            {
                // the user/subject was known, so pass thru (without the redirect claims)
                user.RemoveClaim(user.FindFirst(Constants.ClaimTypes.PartialLoginReturnUrl));
                user.RemoveClaim(user.FindFirst(GetClaimTypeForResumeId(resume)));
                result = new AuthenticateResult(new ClaimsPrincipal(user));
            }
            else
            {
                // the user was not known, we need to re-execute AuthenticateExternalAsync
                // to obtain a subject to proceed
                var provider   = externalProviderClaim.Issuer;
                var providerId = externalProviderClaim.Value;
                var externalId = new ExternalIdentity()
                {
                    Provider = new IdentityProvider {
                        Name = provider
                    },
                    ProviderId = providerId,
                    Claims     = user.Claims
                };

                result = await _userService.AuthenticateExternalAsync(externalId);

                if (result == null)
                {
                    Logger.Warn("user service failed to authenticate external identity");
                    return(await RenderLoginPage(signInMessage, signInId, Messages.NoMatchingExternalAccount));
                }

                if (result.IsError)
                {
                    Logger.WarnFormat("user service returned error message: {0}", result.ErrorMessage);
                    return(await RenderLoginPage(signInMessage, signInId, result.ErrorMessage));
                }
            }

            return(SignInAndRedirect(signInMessage, signInId, result));
        }