Exemplo n.º 1
0
        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());
            }

            if (resume.Length > MaxSignInMessageLength)
            {
                Logger.Error("resumeId length longer than allowed length");
                return(RenderErrorPage());
            }

            var user = await context.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 signInMessage = signInMessageCookie.Read(signInId);

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

            AuthenticateResult result = null;

            // determine which return path the user is taking -- are they coming from
            // a ExternalProvider partial logon, or not
            var externalProviderClaim = user.FindFirst(Constants.ClaimTypes.ExternalProviderUserId);

            // cleanup the claims from the partial login
            if (user.HasClaim(c => c.Type == Constants.ClaimTypes.PartialLoginRestartUrl))
            {
                user.RemoveClaim(user.FindFirst(Constants.ClaimTypes.PartialLoginRestartUrl));
            }
            if (user.HasClaim(c => c.Type == Constants.ClaimTypes.PartialLoginReturnUrl))
            {
                user.RemoveClaim(user.FindFirst(Constants.ClaimTypes.PartialLoginReturnUrl));
            }
            if (user.HasClaim(c => c.Type == Constants.ClaimTypes.ExternalProviderUserId))
            {
                user.RemoveClaim(user.FindFirst(Constants.ClaimTypes.ExternalProviderUserId));
            }
            if (user.HasClaim(c => c.Type == GetClaimTypeForResumeId(resume)))
            {
                user.RemoveClaim(user.FindFirst(GetClaimTypeForResumeId(resume)));
            }

            if (externalProviderClaim != null)
            {
                Logger.Info("using ExternalProviderUserId to call AuthenticateExternalAsync");

                var provider         = externalProviderClaim.Issuer;
                var providerId       = externalProviderClaim.Value;
                var externalIdentity = new ExternalIdentity
                {
                    Provider   = provider,
                    ProviderId = providerId,
                    Claims     = user.Claims
                };

                Logger.InfoFormat("external user provider: {0}, provider ID: {1}", externalIdentity.Provider, externalIdentity.ProviderId);

                var externalContext = new ExternalAuthenticationContext
                {
                    ExternalIdentity = externalIdentity,
                    SignInMessage    = signInMessage
                };

                await userService.AuthenticateExternalAsync(externalContext);

                result = externalContext.AuthenticateResult;
                if (result == null)
                {
                    Logger.Warn("user service failed to authenticate external identity");

                    var msg = localizationService.GetMessage(MessageIds.NoMatchingExternalAccount);
                    await eventService.RaiseExternalLoginFailureEventAsync(externalIdentity, signInId, signInMessage, msg);

                    return(await RenderLoginPage(signInMessage, signInId, msg));
                }

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

                    await eventService.RaiseExternalLoginFailureEventAsync(externalIdentity, signInId, signInMessage, result.ErrorMessage);

                    return(await RenderLoginPage(signInMessage, signInId, result.ErrorMessage));
                }

                Logger.Info("External identity successfully validated by user service");

                await eventService.RaiseExternalLoginSuccessEventAsync(externalIdentity, signInId, signInMessage, result);
            }
            else
            {
                // check to see if the resultant user has all the claim types needed to login
                if (!Constants.AuthenticateResultClaimTypes.All(claimType => user.HasClaim(c => c.Type == claimType)))
                {
                    Logger.Error("Missing AuthenticateResultClaimTypes -- rendering error page");
                    return(RenderErrorPage());
                }

                // this is a normal partial login continuation
                Logger.Info("Partial login resume success -- logging user in");

                result = new AuthenticateResult(new ClaimsPrincipal(user));

                await eventService.RaisePartialLoginCompleteEventAsync(result.User.Identities.First(), signInId, signInMessage);
            }

            // check to see if user clicked "remember me" on login page
            bool?rememberMe = await context.GetPartialLoginRememberMeAsync();

            return(await SignInAndRedirectAsync(signInMessage, signInId, result, rememberMe));
        }
        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());
            }

            if (resume.Length > MaxInputParamLength)
            {
                Logger.Error("resumeId length longer than allowed length");
                return(RenderErrorPage());
            }

            var user = await context.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 signInMessage = signInMessageCookie.Read(signInId);

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

            // check to see if the partial login has all the claim types needed to login
            AuthenticateResult result = null;

            if (Constants.AuthenticateResultClaimTypes.All(claimType => user.HasClaim(claimType)))
            {
                Logger.Info("Authentication claims found -- logging user in");

                // the user/subject was known, so pass thru (without the redirect claims)
                if (user.HasClaim(Constants.ClaimTypes.PartialLoginReturnUrl))
                {
                    user.RemoveClaim(user.FindFirst(Constants.ClaimTypes.PartialLoginReturnUrl));
                }
                if (user.HasClaim(Constants.ClaimTypes.ExternalProviderUserId))
                {
                    user.RemoveClaim(user.FindFirst(Constants.ClaimTypes.ExternalProviderUserId));
                }
                if (user.HasClaim(GetClaimTypeForResumeId(resume)))
                {
                    user.RemoveClaim(user.FindFirst(GetClaimTypeForResumeId(resume)));
                }

                result = new AuthenticateResult(new ClaimsPrincipal(user));

                eventService.RaisePartialLoginCompleteEvent(user, signInId, signInMessage);
            }
            else
            {
                Logger.Info("Authentication claims not found -- looking for ExternalProviderUserId to call AuthenticateExternalAsync");

                // the user was not known, we need to re-execute AuthenticateExternalAsync
                // to obtain a subject to proceed
                var externalProviderClaim = user.FindFirst(Constants.ClaimTypes.ExternalProviderUserId);
                if (externalProviderClaim == null)
                {
                    Logger.Error("No ExternalProviderUserId claim found -- rendering error page");
                    return(RenderErrorPage());
                }

                var provider   = externalProviderClaim.Issuer;
                var providerId = externalProviderClaim.Value;
                var externalId = new ExternalIdentity
                {
                    Provider   = provider,
                    ProviderId = providerId,
                    Claims     = user.Claims
                };

                Logger.InfoFormat("external user provider: {0}, provider ID: {1}", externalId.Provider, externalId.ProviderId);

                result = await userService.AuthenticateExternalAsync(externalId, signInMessage);

                if (result == null)
                {
                    Logger.Warn("user service failed to authenticate external identity");

                    var msg = localizationService.GetMessage(MessageIds.NoMatchingExternalAccount);
                    eventService.RaiseExternalLoginFailureEvent(externalId, signInId, signInMessage, msg);

                    return(await RenderLoginPage(signInMessage, signInId, msg));
                }

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

                    eventService.RaiseExternalLoginFailureEvent(externalId, signInId, signInMessage, result.ErrorMessage);

                    return(await RenderLoginPage(signInMessage, signInId, result.ErrorMessage));
                }

                Logger.Info("External identity successfully validated by user service");

                eventService.RaiseExternalLoginSuccessEvent(externalId, signInId, signInMessage, result);
            }

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