public async Task <IActionResult> EndSessionRequestAsync(string partyId)
        {
            logger.ScopeTrace("Up, OIDC End session request.");
            var oidcUpSequenceData = await sequenceLogic.GetSequenceDataAsync <OidcUpSequenceData>(remove : false);

            if (!oidcUpSequenceData.UpPartyId.Equals(partyId, StringComparison.Ordinal))
            {
                throw new Exception("Invalid up-party id.");
            }
            logger.SetScopeProperty("upPartyId", oidcUpSequenceData.UpPartyId);

            var party = await tenantRepository.GetAsync <OidcUpParty>(oidcUpSequenceData.UpPartyId);

            logger.SetScopeProperty("upPartyClientId", party.Client.ClientId);
            ValidatePartyLogoutSupport(party);

            var postLogoutRedirectUrl    = HttpContext.GetUpPartyUrl(party.Name, Constants.Routes.OAuthController, Constants.Endpoints.EndSessionResponse, partyBindingPattern: party.PartyBindingPattern);
            var rpInitiatedLogoutRequest = new RpInitiatedLogoutRequest
            {
                PostLogoutRedirectUri = postLogoutRedirectUrl,
                State = SequenceString
            };

            var session = await sessionUpPartyLogic.GetSessionAsync(party);

            if (session != null)
            {
                try
                {
                    if (!oidcUpSequenceData.SessionId.Equals(session.SessionId, StringComparison.Ordinal))
                    {
                        throw new Exception("Requested session ID do not match up-party session ID.");
                    }
                }
                catch (Exception ex)
                {
                    logger.Warning(ex);
                }

                rpInitiatedLogoutRequest.IdTokenHint = session.IdToken;

                oidcUpSequenceData.SessionDownPartyLinks = session.DownPartyLinks;
                oidcUpSequenceData.SessionClaims         = session.Claims;
                await sequenceLogic.SaveSequenceDataAsync(oidcUpSequenceData);
            }
            logger.ScopeTrace($"Up, End session request '{rpInitiatedLogoutRequest.ToJsonIndented()}'.");

            _ = await sessionUpPartyLogic.DeleteSessionAsync(session);

            await oauthRefreshTokenGrantLogic.DeleteRefreshTokenGrantsAsync(oidcUpSequenceData.SessionId);

            securityHeaderLogic.AddFormActionAllowAll();

            var nameValueCollection = rpInitiatedLogoutRequest.ToDictionary();

            logger.ScopeTrace($"Up, End session request URL '{party.Client.EndSessionUrl}'.");
            logger.ScopeTrace("Up, Sending OIDC End session request.", triggerEvent: true);
            return(await nameValueCollection.ToRedirectResultAsync(party.Client.EndSessionUrl));
        }
Beispiel #2
0
        private async Task <IActionResult> LogoutRequestAsync <T>(SamlUpParty party, Saml2Binding <T> binding, SamlUpSequenceData samlUpSequenceData)
        {
            var samlConfig = await saml2ConfigurationLogic.GetSamlUpConfigAsync(party, includeSigningAndDecryptionCertificate : true);

            binding.RelayState = await sequenceLogic.CreateExternalSequenceIdAsync();

            var saml2LogoutRequest = new Saml2LogoutRequest(samlConfig);

            var session = await sessionUpPartyLogic.GetSessionAsync(party);

            if (session == null)
            {
                return(await LogoutResponseDownAsync(samlUpSequenceData));
            }

            try
            {
                if (!samlUpSequenceData.SessionId.Equals(session.SessionId, StringComparison.Ordinal))
                {
                    throw new Exception("Requested session ID do not match up-party session ID.");
                }
            }
            catch (Exception ex)
            {
                logger.Warning(ex);
            }

            saml2LogoutRequest.SessionIndex = session.ExternalSessionId;

            samlUpSequenceData.SessionDownPartyLinks = session.DownPartyLinks;
            samlUpSequenceData.SessionClaims         = session.Claims;
            await sequenceLogic.SaveSequenceDataAsync(samlUpSequenceData);

            var jwtClaims    = samlUpSequenceData.SessionClaims.ToClaimList();
            var nameID       = jwtClaims?.Where(c => c.Type == JwtClaimTypes.Subject).Select(c => c.Value).FirstOrDefault();
            var nameIdFormat = jwtClaims?.Where(c => c.Type == Constants.JwtClaimTypes.SubFormat).Select(c => c.Value).FirstOrDefault();

            if (!nameID.IsNullOrEmpty())
            {
                var prePartyName = $"{party.Name}|";
                if (nameID.StartsWith(prePartyName, StringComparison.Ordinal))
                {
                    nameID = nameID.Remove(0, prePartyName.Length);
                }
                if (nameIdFormat.IsNullOrEmpty())
                {
                    saml2LogoutRequest.NameId = new Saml2NameIdentifier(nameID);
                }
                else
                {
                    saml2LogoutRequest.NameId = new Saml2NameIdentifier(nameID, new Uri(nameIdFormat));
                }
            }

            binding.Bind(saml2LogoutRequest);
            logger.ScopeTrace(() => $"SAML Logout request '{saml2LogoutRequest.XmlDocument.OuterXml}'.", traceType: TraceTypes.Message);
            logger.ScopeTrace(() => $"Logout URL '{samlConfig.SingleLogoutDestination?.OriginalString}'.");
            logger.ScopeTrace(() => "Up, SAML Logout request.", triggerEvent: true);

            _ = await sessionUpPartyLogic.DeleteSessionAsync(party, session);

            await oauthRefreshTokenGrantLogic.DeleteRefreshTokenGrantsAsync(samlUpSequenceData.SessionId);

            securityHeaderLogic.AddFormActionAllowAll();

            if (binding is Saml2Binding <Saml2RedirectBinding> )
            {
                return(await(binding as Saml2RedirectBinding).ToActionFormResultAsync());
            }
            else if (binding is Saml2Binding <Saml2PostBinding> )
            {
                return(await(binding as Saml2PostBinding).ToActionFormResultAsync());
            }
            else
            {
                throw new NotSupportedException();
            }
        }
        public async Task <IActionResult> FrontChannelLogoutAsync(string partyId)
        {
            logger.ScopeTrace(() => "Up, OIDC Front channel logout.");
            logger.SetScopeProperty(Constants.Logs.UpPartyId, partyId);

            var party = await tenantRepository.GetAsync <OidcUpParty>(partyId);

            logger.SetScopeProperty(Constants.Logs.UpPartyClientId, party.Client.ClientId);

            if (party.Client.DisableFrontChannelLogout)
            {
                return(new BadRequestResult());
            }

            var queryDictionary           = HttpContext.Request.Query.ToDictionary();
            var frontChannelLogoutRequest = queryDictionary.ToObject <FrontChannelLogoutRequest>();

            logger.ScopeTrace(() => $"Up, Front channel logout request '{frontChannelLogoutRequest.ToJsonIndented()}'.", traceType: TraceTypes.Message);
            frontChannelLogoutRequest.Validate();
            if (party.Client.FrontChannelLogoutSessionRequired)
            {
                if (frontChannelLogoutRequest.SessionId.IsNullOrEmpty())
                {
                    throw new ArgumentNullException(nameof(frontChannelLogoutRequest.SessionId), frontChannelLogoutRequest.GetTypeName());
                }
            }

            var session = await sessionUpPartyLogic.GetSessionAsync(party);

            logger.ScopeTrace(() => "Up, Successful OIDC Front channel logout request.", triggerEvent: true);
            if (session != null)
            {
                if (party.Client.FrontChannelLogoutSessionRequired)
                {
                    if (!party.Issuers.Where(i => i == frontChannelLogoutRequest.Issuer).Any())
                    {
                        throw new Exception("Incorrect issuer.");
                    }
                    if (session.ExternalSessionId != frontChannelLogoutRequest.SessionId)
                    {
                        throw new Exception("Incorrect session id.");
                    }
                }

                var _ = await sessionUpPartyLogic.DeleteSessionAsync(party, session);

                await oauthRefreshTokenGrantLogic.DeleteRefreshTokenGrantsAsync(session.SessionId);

                if (!party.DisableSingleLogout)
                {
                    var allowIframeOnDomains = new List <string>().ConcatOnce(party.Client.AuthorizeUrl?.UrlToDomain()).ConcatOnce(party.Client.EndSessionUrl?.UrlToDomain()).ConcatOnce(party.Client.TokenUrl?.UrlToDomain());
                    (var doSingleLogout, var singleLogoutSequenceData) = await singleLogoutDownLogic.InitializeSingleLogoutAsync(new UpPartyLink { Name = party.Name, Type = party.Type }, null, session.DownPartyLinks, session.Claims, allowIframeOnDomains, hostedInIframe : true);

                    if (doSingleLogout)
                    {
                        return(await singleLogoutDownLogic.StartSingleLogoutAsync(singleLogoutSequenceData));
                    }
                }
            }

            return(new OkResult());
        }
Beispiel #4
0
        public async Task <IActionResult> FrontChannelLogoutAsync(string partyId)
        {
            logger.ScopeTrace("Up, OIDC Front channel logout.");
            logger.SetScopeProperty("upPartyId", partyId);

            var party = await tenantRepository.GetAsync <OidcUpParty>(partyId);

            logger.SetScopeProperty("upPartyClientId", party.Client.ClientId);

            if (party.Client.DisableFrontChannelLogout)
            {
                return(new BadRequestResult());
            }

            var queryDictionary           = HttpContext.Request.Query.ToDictionary();
            var frontChannelLogoutRequest = queryDictionary.ToObject <FrontChannelLogoutRequest>();

            logger.ScopeTrace($"Up, Front channel logout request '{frontChannelLogoutRequest.ToJsonIndented()}'.");
            frontChannelLogoutRequest.Validate();
            if (party.Client.FrontChannelLogoutSessionRequired)
            {
                if (frontChannelLogoutRequest.SessionId.IsNullOrEmpty())
                {
                    throw new ArgumentNullException(nameof(frontChannelLogoutRequest.SessionId), frontChannelLogoutRequest.GetTypeName());
                }
            }

            var session = await sessionUpPartyLogic.GetSessionAsync(party);

            logger.ScopeTrace("Up, Successful OIDC Front channel logout request.", triggerEvent: true);
            if (session != null)
            {
                if (party.Client.FrontChannelLogoutSessionRequired)
                {
                    if (!session.Claims.Where(c => c.Claim == JwtClaimTypes.Issuer && c.Values.Where(v => v == frontChannelLogoutRequest.Issuer).Any()).Any())
                    {
                        throw new Exception("Incorrect issuer.");
                    }
                    if (session.ExternalSessionId != frontChannelLogoutRequest.SessionId)
                    {
                        throw new Exception("Incorrect session id.");
                    }
                }

                var _ = await sessionUpPartyLogic.DeleteSessionAsync(session);

                await oauthRefreshTokenGrantLogic.DeleteRefreshTokenGrantsAsync(session.SessionId);

                if (!party.DisableSingleLogout)
                {
                    (var doSingleLogout, var singleLogoutSequenceData) = await singleLogoutDownLogic.InitializeSingleLogoutAsync(new UpPartyLink { Name = party.Name, Type = party.Type }, null, session.DownPartyLinks, session.Claims, redirectAfterLogout : false);

                    if (doSingleLogout)
                    {
                        securityHeaderLogic.AddAllowIframeOnUrls(new [] { party.Client.AuthorizeUrl, party.Client.EndSessionUrl });
                        return(await singleLogoutDownLogic.StartSingleLogoutAsync(singleLogoutSequenceData));
                    }
                }
            }

            return(new OkResult());
        }