public async Task <(bool, SingleLogoutSequenceData)> InitializeSingleLogoutAsync(UpPartyLink upPartyLink, DownPartySessionLink initiatingDownParty, IEnumerable <DownPartySessionLink> downPartyLinks, IEnumerable <ClaimAndValues> claims, IEnumerable <string> allowIframeOnDomains = null, bool hostedInIframe = false)
        {
            logger.ScopeTrace(() => "Initialize single logout.");

            downPartyLinks = downPartyLinks?.Where(p => p.SupportSingleLogout && (initiatingDownParty == null || p.Id != initiatingDownParty.Id));
            if (!(downPartyLinks?.Count() > 0) || !(claims?.Count() > 0))
            {
                return(false, null);
            }

            var sequenceData = new SingleLogoutSequenceData
            {
                UpPartyName          = upPartyLink.Name,
                UpPartyType          = upPartyLink.Type,
                DownPartyLinks       = downPartyLinks,
                HostedInIframe       = hostedInIframe,
                AllowIframeOnDomains = allowIframeOnDomains
            };

            if (downPartyLinks.Where(p => p.Type == PartyTypes.Saml2).Any())
            {
                sequenceData.Claims = claims;
            }
            else
            {
                sequenceData.Claims = claims.Where(c => c.Claim == JwtClaimTypes.SessionId);
            }

            await sequenceLogic.SaveSequenceDataAsync(sequenceData);

            return(true, sequenceData);
        }
Beispiel #2
0
        public async Task <IActionResult> SingleLogoutRequestAsync(string partyId, SingleLogoutSequenceData sequenceData)
        {
            logger.ScopeTrace("Down, SAML Single Logout request.");
            logger.SetScopeProperty("downPartyId", partyId);
            var party = await tenantRepository.GetAsync <SamlDownParty>(partyId);

            if (!ValidatePartySingleLogoutSupport(party))
            {
                return(await singleLogoutDownLogic.HandleSingleLogoutAsync(sequenceData));
            }

            var claims = await claimsDownLogic.FromJwtToSamlClaimsAsync(sequenceData.Claims.ToClaimList());

            switch (party.LogoutBinding.RequestBinding)
            {
            case SamlBindingTypes.Redirect:
                return(await SingleLogoutRequestAsync(party, new Saml2RedirectBinding(), claims));

            case SamlBindingTypes.Post:
                return(await SingleLogoutRequestAsync(party, new Saml2PostBinding(), claims));

            default:
                throw new NotSupportedException($"SAML binding '{party.LogoutBinding.RequestBinding}' not supported.");
            }
        }
        public async Task <IActionResult> HandleSingleLogoutAsync(SingleLogoutSequenceData sequenceData = null)
        {
            sequenceData = sequenceData ?? await sequenceLogic.GetSequenceDataAsync <SingleLogoutSequenceData>(remove : false);

            if (sequenceData.HostedInIframe && sequenceData.AllowIframeOnDomains?.Count() > 0)
            {
                securityHeaderLogic.AddAllowIframeOnDomains(sequenceData.AllowIframeOnDomains);
            }

            var samlDownPartyId = sequenceData.DownPartyLinks.Where(p => p.Type == PartyTypes.Saml2).Select(p => p.Id).FirstOrDefault();

            var oidcDownPartyIds = sequenceData.DownPartyLinks.Where(p => p.Type == PartyTypes.Oidc).Select(p => p.Id);

            if (oidcDownPartyIds.Count() > 0)
            {
                sequenceData.DownPartyLinks = sequenceData.DownPartyLinks.Where(p => p.Type != PartyTypes.Oidc);
                await sequenceLogic.SaveSequenceDataAsync(sequenceData);

                var doSamlLogoutInIframe = sequenceData.HostedInIframe && samlDownPartyId != null;
                return(await serviceProvider.GetService <OidcFrontChannelLogoutDownLogic <OidcDownParty, OidcDownClient, OidcDownScope, OidcDownClaim> >().LogoutRequestAsync(oidcDownPartyIds, sequenceData, sequenceData.HostedInIframe, doSamlLogoutInIframe));
            }

            if (samlDownPartyId != null)
            {
                sequenceData.DownPartyLinks = sequenceData.DownPartyLinks.Where(p => p.Id != samlDownPartyId);
                await sequenceLogic.SaveSequenceDataAsync(sequenceData);

                return(await serviceProvider.GetService <SamlLogoutDownLogic>().SingleLogoutRequestAsync(samlDownPartyId, sequenceData));
            }

            await sequenceLogic.RemoveSequenceDataAsync <SingleLogoutSequenceData>();

            logger.ScopeTrace(() => "Successful Single Logout.", triggerEvent: true);

            if (sequenceData.HostedInIframe)
            {
                return(new OkResult());
            }
            else
            {
                return(await ResponseUpPartyAsync(sequenceData.UpPartyName, sequenceData.UpPartyType));
            }
        }
 public async Task <IActionResult> StartSingleLogoutAsync(SingleLogoutSequenceData sequenceData)
 {
     logger.ScopeTrace(() => "Start single logout.");
     return(await HandleSingleLogoutAsync(sequenceData));
 }
Beispiel #5
0
        public async Task <IActionResult> LogoutRequestAsync(IEnumerable <string> partyIds, SingleLogoutSequenceData sequenceData)
        {
            var frontChannelLogoutRequest = new FrontChannelLogoutRequest
            {
                Issuer    = trackIssuerLogic.GetIssuer(),
                SessionId = sequenceData.Claims.FindFirstValue(c => c.Claim == JwtClaimTypes.SessionId)
            };
            var nameValueCollection = frontChannelLogoutRequest.ToDictionary();

            TParty firstParty      = null;
            var    partyLogoutUrls = new List <string>();

            foreach (var partyId in partyIds)
            {
                try
                {
                    var party = await tenantRepository.GetAsync <TParty>(partyId);

                    if (party.Client == null)
                    {
                        throw new NotSupportedException("Party Client not configured.");
                    }
                    if (party.Client.FrontChannelLogoutUri.IsNullOrWhiteSpace())
                    {
                        throw new Exception("Front channel logout URI not configured.");
                    }

                    firstParty = party;
                    if (party.Client.FrontChannelLogoutSessionRequired)
                    {
                        partyLogoutUrls.Add(QueryHelpers.AddQueryString(party.Client.FrontChannelLogoutUri, nameValueCollection));
                    }
                    else
                    {
                        partyLogoutUrls.Add(party.Client.FrontChannelLogoutUri);
                    }
                }
                catch (Exception ex)
                {
                    logger.Warning(ex, $"Unable to get front channel logout for party ID '{partyId}'.");
                }
            }

            if (partyLogoutUrls.Count() <= 0 || firstParty == null)
            {
                throw new InvalidOperationException("Unable to complete front channel logout. Please close the browser to logout.");
            }

            securityHeaderLogic.AddFrameSrc(partyLogoutUrls);
            var redirectUrl = HttpContext.GetDownPartyUrl(firstParty.Name, sequenceData.UpPartyName, Constants.Routes.OAuthController, Constants.Endpoints.FrontChannelLogoutDone, includeSequence: true);

            return(partyLogoutUrls.ToHtmIframePage(redirectUrl, "FoxIDs").ToContentResult());
        }
Beispiel #6
0
 private string GetFrontChannelLogoutDoneUrl(SingleLogoutSequenceData sequenceData, TParty firstParty)
 {
     return(HttpContext.GetDownPartyUrl(firstParty.Name, sequenceData.UpPartyName, Constants.Routes.OAuthController, Constants.Endpoints.FrontChannelLogoutDone, includeSequence: true));
 }
Beispiel #7
0
        public async Task <IActionResult> LogoutRequestAsync(IEnumerable <string> partyIds, SingleLogoutSequenceData sequenceData, bool hostedInIframe, bool doSamlLogoutInIframe)
        {
            var frontChannelLogoutRequest = new FrontChannelLogoutRequest
            {
                Issuer    = trackIssuerLogic.GetIssuer(),
                SessionId = sequenceData.Claims.FindFirstValue(c => c.Claim == JwtClaimTypes.SessionId)
            };
            var nameValueCollection = frontChannelLogoutRequest.ToDictionary();

            TParty firstParty      = null;
            var    partyLogoutUrls = new List <string>();

            foreach (var partyId in partyIds)
            {
                try
                {
                    var party = await tenantRepository.GetAsync <TParty>(partyId);

                    if (party.Client == null)
                    {
                        throw new NotSupportedException("Party Client not configured.");
                    }
                    if (party.Client.FrontChannelLogoutUri.IsNullOrWhiteSpace())
                    {
                        throw new Exception("Front channel logout URI not configured.");
                    }

                    firstParty = party;
                    if (party.Client.FrontChannelLogoutSessionRequired)
                    {
                        partyLogoutUrls.Add(QueryHelpers.AddQueryString(party.Client.FrontChannelLogoutUri, nameValueCollection));
                    }
                    else
                    {
                        partyLogoutUrls.Add(party.Client.FrontChannelLogoutUri);
                    }
                }
                catch (Exception ex)
                {
                    logger.Warning(ex, $"Unable to get front channel logout for party ID '{partyId}'.");
                }
            }

            if (partyLogoutUrls.Count() <= 0 || firstParty == null)
            {
                throw new InvalidOperationException("Unable to complete front channel logout. Please close the browser to logout.");
            }

            if (doSamlLogoutInIframe)
            {
                securityHeaderLogic.AddFrameSrcAllowAll();
                // Start SAML logout
                partyLogoutUrls.Add(GetFrontChannelLogoutDoneUrl(sequenceData, firstParty));
            }
            else
            {
                securityHeaderLogic.AddFrameSrcUrls(partyLogoutUrls);
            }
            string redirectUrl = hostedInIframe ? null : GetFrontChannelLogoutDoneUrl(sequenceData, firstParty);

            return(partyLogoutUrls.ToHtmIframePage(redirectUrl, "FoxIDs").ToContentResult());
        }