Example #1
0
        public async Task <IActionResult> LogoutRequestRedirectAsync(UpPartyLink partyLink, LogoutRequest logoutRequest)
        {
            logger.ScopeTrace(() => "Up, SAML Logout request.");
            var partyId = await UpParty.IdFormatAsync(RouteBinding, partyLink.Name);

            logger.SetScopeProperty(Constants.Logs.UpPartyId, partyId);

            await logoutRequest.ValidateObjectAsync();

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

            await sequenceLogic.SaveSequenceDataAsync(new SamlUpSequenceData
            {
                DownPartyLink        = logoutRequest.DownPartyLink,
                UpPartyId            = partyId,
                SessionId            = logoutRequest.SessionId,
                RequireLogoutConsent = logoutRequest.RequireLogoutConsent,
                PostLogoutRedirect   = logoutRequest.PostLogoutRedirect,
                Claims = logoutRequest.Claims.ToClaimAndValues()
            });

            return(HttpContext.GetUpPartyUrl(partyLink.Name, Constants.Routes.SamlUpJumpController, Constants.Endpoints.UpJump.LogoutRequest, includeSequence: true, partyBindingPattern: party.PartyBindingPattern).ToRedirectResult());
        }
Example #2
0
        public async Task <IActionResult> AuthenticationRequestRedirectAsync(UpPartyLink partyLink, LoginRequest loginRequest)
        {
            logger.ScopeTrace(() => "Up, OIDC Authentication request redirect.");
            var partyId = await UpParty.IdFormatAsync(RouteBinding, partyLink.Name);

            logger.SetScopeProperty(Constants.Logs.UpPartyId, partyId);

            await loginRequest.ValidateObjectAsync();

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

            var oidcUpSequenceData = new OidcUpSequenceData
            {
                DownPartyLink = loginRequest.DownPartyLink,
                UpPartyId     = partyId,
                LoginAction   = loginRequest.LoginAction,
                UserId        = loginRequest.UserId,
                MaxAge        = loginRequest.MaxAge
            };
            await sequenceLogic.SaveSequenceDataAsync(oidcUpSequenceData);

            return(HttpContext.GetUpPartyUrl(partyLink.Name, Constants.Routes.OAuthUpJumpController, Constants.Endpoints.UpJump.AuthenticationRequest, includeSequence: true, partyBindingPattern: party.PartyBindingPattern).ToRedirectResult());
        }
Example #3
0
        public async Task <IActionResult> LogoutRequestAsync(string partyId)
        {
            logger.ScopeTrace("Down, SAML Logout request.");
            logger.SetScopeProperty("downPartyId", partyId);
            var party = await tenantRepository.GetAsync <SamlDownParty>(partyId);

            ValidatePartyLogoutSupport(party);

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

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

            default:
                throw new NotSupportedException($"SAML binding '{party.LogoutBinding.RequestBinding}' not supported.");
            }
        }
        public async Task <IActionResult> EndSessionRequestAsync(string partyId)
        {
            logger.ScopeTrace("Down, End session request.");
            logger.SetScopeProperty("downPartyId", partyId);
            var party = await tenantRepository.GetAsync <TParty>(partyId);

            if (party.Client == null)
            {
                throw new NotSupportedException("Party Client not configured.");
            }

            var formOrQueryDictionary = HttpContext.Request.Method switch
            {
                "POST" => party.Client.ResponseMode == IdentityConstants.ResponseModes.FormPost ? HttpContext.Request.Form.ToDictionary() : throw new NotSupportedException($"POST not supported by response mode '{party.Client.ResponseMode}'."),
                      "GET" => party.Client.ResponseMode == IdentityConstants.ResponseModes.Query ? HttpContext.Request.Query.ToDictionary() : throw new NotSupportedException($"GET not supported by response mode '{party.Client.ResponseMode}'."),
                            _ => throw new NotSupportedException($"Request method not supported by response mode '{party.Client.ResponseMode}'")
            };

            var rpInitiatedLogoutRequest = formOrQueryDictionary.ToObject <RpInitiatedLogoutRequest>();

            logger.ScopeTrace($"end session request '{rpInitiatedLogoutRequest.ToJsonIndented()}'.");
            logger.SetScopeProperty("downPartyClientId", party.Client.ClientId);

            ValidateEndSessionRequest(party.Client, rpInitiatedLogoutRequest);
            logger.ScopeTrace("Down, OIDC End session request accepted.", triggerEvent: true);

            (var validIdToken, var sessionId, var idTokenClaims) = await ValidateIdTokenHintAsync(party.Client, rpInitiatedLogoutRequest.IdTokenHint);

            if (!validIdToken)
            {
                if (party.Client.RequireLogoutIdTokenHint)
                {
                    if (!rpInitiatedLogoutRequest.IdTokenHint.IsNullOrEmpty())
                    {
                        throw new OAuthRequestException($"Invalid ID Token hint.")
                              {
                                  RouteBinding = RouteBinding
                              };
                    }

                    throw new OAuthRequestException($"ID Token hint is required.")
                          {
                              RouteBinding = RouteBinding
                          };
                }
            }
            else
            {
                logger.ScopeTrace("Valid ID token hint.");
            }

            var postLogoutRedirectUri = !rpInitiatedLogoutRequest.PostLogoutRedirectUri.IsNullOrWhiteSpace() ? rpInitiatedLogoutRequest.PostLogoutRedirectUri : party.Client.PostLogoutRedirectUri;
            await sequenceLogic.SaveSequenceDataAsync(new OidcDownSequenceData
            {
                RedirectUri = postLogoutRedirectUri,
                State       = rpInitiatedLogoutRequest.State,
            });

            var toUpPartie = GetToUpParty(idTokenClaims);

            logger.ScopeTrace($"Request, Up type '{toUpPartie.Type}'.");
            switch (toUpPartie.Type)
            {
            case PartyTypes.Login:
                return(await serviceProvider.GetService <LogoutUpLogic>().LogoutRedirect(toUpPartie, GetLogoutRequest(party, sessionId, validIdToken, postLogoutRedirectUri)));

            case PartyTypes.OAuth2:
                throw new NotImplementedException();

            case PartyTypes.Oidc:
                return(await serviceProvider.GetService <OidcRpInitiatedLogoutUpLogic <OidcUpParty, OidcUpClient> >().EndSessionRequestRedirectAsync(toUpPartie, GetLogoutRequest(party, sessionId, validIdToken, postLogoutRedirectUri)));

            case PartyTypes.Saml2:
                if (!validIdToken)
                {
                    throw new OAuthRequestException($"ID Token hint is required for SAML 2.0 Up-party.")
                          {
                              RouteBinding = RouteBinding
                          };
                }
                return(await serviceProvider.GetService <SamlLogoutUpLogic>().LogoutRequestRedirectAsync(toUpPartie, GetSamlLogoutRequest(party, sessionId, idTokenClaims)));

            default:
                throw new NotSupportedException($"Party type '{toUpPartie.Type}' not supported.");
            }
        }
Example #5
0
        public override async Task <IActionResult> TokenRequestAsync(string partyId)
        {
            logger.ScopeTrace(() => "Down, OIDC Token request.");
            logger.SetScopeProperty(Constants.Logs.DownPartyId, partyId);
            var party = await tenantRepository.GetAsync <TParty>(partyId);

            if (party.Client == null)
            {
                throw new NotSupportedException("Party Client not configured.");
            }
            logger.SetScopeProperty(Constants.Logs.DownPartyClientId, party.Client.ClientId);

            var formDictionary = HttpContext.Request.Form.ToDictionary();
            var tokenRequest   = formDictionary.ToObject <TokenRequest>();

            logger.ScopeTrace(() => $"Down, Token request '{tokenRequest.ToJsonIndented()}'.", traceType: TraceTypes.Message);

            var clientCredentials = formDictionary.ToObject <ClientCredentials>();

            logger.ScopeTrace(() => $"Down, Client credentials '{new ClientCredentials { ClientSecret = $"{(clientCredentials.ClientSecret?.Length > 10 ? clientCredentials.ClientSecret.Substring(0, 3) : string.Empty)}..." }.ToJsonIndented()}'.", traceType: TraceTypes.Message);

            var codeVerifierSecret = party.Client.RequirePkce ? formDictionary.ToObject <CodeVerifierSecret>() : null;

            if (codeVerifierSecret != null)
            {
                logger.ScopeTrace(() => $"Down, Code verifier secret '{new CodeVerifierSecret { CodeVerifier = $"{(codeVerifierSecret.CodeVerifier?.Length > 10 ? codeVerifierSecret.CodeVerifier.Substring(0, 3) : string.Empty)}..." }.ToJsonIndented()}'.", traceType: TraceTypes.Message);
            }

            try
            {
                logger.SetScopeProperty(Constants.Logs.GrantType, tokenRequest.GrantType);
                switch (tokenRequest.GrantType)
                {
                case IdentityConstants.GrantTypes.AuthorizationCode:
                    ValidateAuthCodeRequest(party.Client, tokenRequest);
                    var validatePkce = party.Client.RequirePkce && codeVerifierSecret != null;
                    await ValidateSecretAsync(party.Client, tokenRequest, clientCredentials, secretValidationRequired : !validatePkce);

                    return(await AuthorizationCodeGrantAsync(party.Client, tokenRequest, validatePkce, codeVerifierSecret));

                case IdentityConstants.GrantTypes.RefreshToken:
                    ValidateRefreshTokenRequest(party.Client, tokenRequest);
                    await ValidateSecretAsync(party.Client, tokenRequest, clientCredentials, secretValidationRequired : !party.Client.RequirePkce);

                    return(await RefreshTokenGrantAsync(party.Client, tokenRequest));

                case IdentityConstants.GrantTypes.ClientCredentials:
                    ValidateClientCredentialsRequest(party.Client, tokenRequest);
                    await ValidateSecretAsync(party.Client, tokenRequest, clientCredentials);

                    return(await ClientCredentialsGrantAsync(party, tokenRequest));

                case IdentityConstants.GrantTypes.Delegation:
                    throw new NotImplementedException();

                default:
                    throw new OAuthRequestException($"Unsupported grant type '{tokenRequest.GrantType}'.")
                          {
                              RouteBinding = RouteBinding, Error = IdentityConstants.ResponseErrors.UnsupportedGrantType
                          };
                }
            }
            catch (ArgumentException ex)
            {
                throw new OAuthRequestException(ex.Message, ex)
                      {
                          RouteBinding = RouteBinding, Error = IdentityConstants.ResponseErrors.InvalidRequest
                      };
            }
        }
Example #6
0
        public override async Task <IActionResult> TokenRequestAsync(string partyId)
        {
            logger.ScopeTrace("Down, OIDC Token request.");
            logger.SetScopeProperty("downPartyId", partyId);
            var party = await tenantRepository.GetAsync <TParty>(partyId);

            if (party.Client == null)
            {
                throw new NotSupportedException($"Party Client not configured.");
            }

            var formDictionary = HttpContext.Request.Form.ToDictionary();
            var tokenRequest   = formDictionary.ToObject <TokenRequest>();

            logger.ScopeTrace($"Token request '{tokenRequest.ToJsonIndented()}'.");
            logger.SetScopeProperty("clientId", tokenRequest.ClientId);

            var clientCredentials = formDictionary.ToObject <ClientCredentials>();

            var codeVerifierSecret = party.Client.EnablePkce.Value ? formDictionary.ToObject <CodeVerifierSecret>() : null;

            try
            {
                logger.SetScopeProperty("GrantType", tokenRequest.GrantType);
                switch (tokenRequest.GrantType)
                {
                case IdentityConstants.GrantTypes.AuthorizationCode:
                    ValidateAuthCodeRequest(party.Client, tokenRequest);
                    var validatePkce = party.Client.EnablePkce.Value && codeVerifierSecret != null;
                    if (!validatePkce)
                    {
                        await ValidateSecret(party.Client, tokenRequest, clientCredentials);
                    }
                    return(await AuthorizationCodeGrant(party.Client, tokenRequest, validatePkce, codeVerifierSecret));

                case IdentityConstants.GrantTypes.RefreshToken:
                    ValidateRefreshTokenRequest(party.Client, tokenRequest);
                    if (!party.Client.EnablePkce.Value)
                    {
                        await ValidateSecret(party.Client, tokenRequest, clientCredentials);
                    }
                    return(await RefreshTokenGrant(party.Client, tokenRequest));

                case IdentityConstants.GrantTypes.ClientCredentials:
                    ValidateClientCredentialsRequest(party.Client, tokenRequest);
                    await ValidateSecret(party.Client, tokenRequest, clientCredentials);

                    return(await ClientCredentialsGrant(party.Client, tokenRequest));

                case IdentityConstants.GrantTypes.Delegation:
                    throw new NotImplementedException();

                default:
                    throw new OAuthRequestException($"Unsupported grant type '{tokenRequest.GrantType}'.")
                          {
                              RouteBinding = RouteBinding, Error = IdentityConstants.ResponseErrors.UnsupportedGrantType
                          };
                }
            }
            catch (ArgumentException ex)
            {
                throw new OAuthRequestException(ex.Message, ex)
                      {
                          RouteBinding = RouteBinding, Error = IdentityConstants.ResponseErrors.InvalidRequest
                      };
            }
        }
Example #7
0
        public async Task <IActionResult> AuthenticationRequestAsync(string partyId)
        {
            logger.ScopeTrace("Down, OIDC Authentication request.");
            logger.SetScopeProperty("downPartyId", partyId);
            var party = await tenantRepository.GetAsync <TParty>(partyId);

            if (party.Client == null)
            {
                throw new NotSupportedException($"Party Client not configured.");
            }

            var queryDictionary       = HttpContext.Request.Query.ToDictionary();
            var authenticationRequest = queryDictionary.ToObject <AuthenticationRequest>();

            logger.ScopeTrace($"Authentication request '{authenticationRequest.ToJsonIndented()}'.");
            logger.SetScopeProperty("clientId", authenticationRequest.ClientId);

            var codeChallengeSecret = party.Client.EnablePkce.Value ? queryDictionary.ToObject <CodeChallengeSecret>() : null;

            if (codeChallengeSecret != null)
            {
                codeChallengeSecret.Validate();
                logger.ScopeTrace($"CodeChallengeSecret '{codeChallengeSecret.ToJsonIndented()}'.");
            }

            try
            {
                var requireCodeFlow = party.Client.EnablePkce.Value && codeChallengeSecret != null;
                ValidateAuthenticationRequest(party.Client, authenticationRequest, requireCodeFlow);
                logger.ScopeTrace("Down, OIDC Authentication request accepted.", triggerEvent: true);

                if (!authenticationRequest.UiLocales.IsNullOrWhiteSpace())
                {
                    await sequenceLogic.SetCultureAsync(authenticationRequest.UiLocales.ToSpaceList());
                }

                await sequenceLogic.SaveSequenceDataAsync(new OidcDownSequenceData
                {
                    ResponseType        = authenticationRequest.ResponseType,
                    RedirectUri         = authenticationRequest.RedirectUri,
                    Scope               = authenticationRequest.Scope,
                    State               = authenticationRequest.State,
                    ResponseMode        = authenticationRequest.ResponseMode,
                    Nonce               = authenticationRequest.Nonce,
                    CodeChallenge       = codeChallengeSecret?.CodeChallenge,
                    CodeChallengeMethod = codeChallengeSecret?.CodeChallengeMethod,
                });

                await formActionLogic.CreateFormActionByUrlAsync(authenticationRequest.RedirectUri);

                var type = RouteBinding.ToUpParties.First().Type;
                logger.ScopeTrace($"Request, Up type '{type}'.");
                switch (type)
                {
                case PartyTypes.Login:
                    return(await serviceProvider.GetService <LoginUpLogic>().LoginRedirectAsync(RouteBinding.ToUpParties.First(), await GetLoginRequestAsync(party, authenticationRequest)));

                case PartyTypes.OAuth2:
                    throw new NotImplementedException();

                case PartyTypes.Oidc:
                    return(await serviceProvider.GetService <OidcAuthUpLogic <OidcDownParty, OidcDownClient, OidcDownScope, OidcDownClaim> >().AuthenticationRequestAsync(RouteBinding.ToUpParties.First()));

                case PartyTypes.Saml2:
                    return(await serviceProvider.GetService <SamlAuthnUpLogic>().AuthnRequestAsync(RouteBinding.ToUpParties.First(), await GetLoginRequestAsync(party, authenticationRequest)));

                default:
                    throw new NotSupportedException($"Party type '{type}' not supported.");
                }
            }
            catch (OAuthRequestException ex)
            {
                logger.Error(ex);
                return(await AuthenticationResponseErrorAsync(partyId, authenticationRequest, ex));
            }
        }
Example #8
0
        public async Task <IActionResult> EndSessionRequestAsync(string partyId)
        {
            logger.ScopeTrace("Down, End session request.");
            logger.SetScopeProperty("downPartyId", partyId);
            var party = await tenantRepository.GetAsync <TParty>(partyId);

            if (party.Client == null)
            {
                throw new NotSupportedException($"Party Client not configured.");
            }

            var endSessionRequest = HttpContext.Request.Query.ToObject <EndSessionRequest>();

            logger.ScopeTrace($"end session request '{endSessionRequest.ToJsonIndented()}'.");
            logger.SetScopeProperty("clientId", party.Client.ClientId);

            ValidateEndSessionRequest(party.Client, endSessionRequest);
            logger.ScopeTrace("Down, OIDC End session request accepted.", triggerEvent: true);

            (var validIdToken, var sessionId, var idTokenClaims) = await ValidateIdTokenHintAsync(party.Client, endSessionRequest.IdTokenHint);

            if (!validIdToken)
            {
                if (!endSessionRequest.IdTokenHint.IsNullOrEmpty())
                {
                    throw new OAuthRequestException($"Invalid ID Token hint.")
                          {
                              RouteBinding = RouteBinding
                          };
                }
                else if (party.Client.RequireLogoutIdTokenHint)
                {
                    throw new OAuthRequestException($"ID Token hint is required.")
                          {
                              RouteBinding = RouteBinding
                          };
                }
            }
            else
            {
                logger.ScopeTrace("Valid ID token hint.");
            }

            await oauthRefreshTokenGrantLogic.DeleteRefreshTokenGrantAsync(party.Client, sessionId);

            await sequenceLogic.SaveSequenceDataAsync(new OidcDownSequenceData
            {
                RedirectUri = endSessionRequest.PostLogoutRedirectUri,
                State       = endSessionRequest.State,
            });

            await formActionLogic.CreateFormActionByUrlAsync(endSessionRequest.PostLogoutRedirectUri);

            var type = RouteBinding.ToUpParties.First().Type;

            logger.ScopeTrace($"Request, Up type '{type}'.");
            switch (type)
            {
            case PartyTypes.Login:
                var logoutRequest = new LogoutRequest
                {
                    DownParty            = party,
                    SessionId            = sessionId,
                    RequireLogoutConsent = !validIdToken,
                    PostLogoutRedirect   = !endSessionRequest.PostLogoutRedirectUri.IsNullOrWhiteSpace(),
                };
                return(await serviceProvider.GetService <LogoutUpLogic>().LogoutRedirect(RouteBinding.ToUpParties.First(), logoutRequest));

            case PartyTypes.OAuth2:
                throw new NotImplementedException();

            case PartyTypes.Oidc:
                throw new NotImplementedException();

            case PartyTypes.Saml2:
                if (!validIdToken)
                {
                    throw new OAuthRequestException($"ID Token hint is required for SAML 2.0 Up Party.")
                          {
                              RouteBinding = RouteBinding
                          };
                }
                return(await serviceProvider.GetService <SamlLogoutUpLogic>().LogoutAsync(RouteBinding.ToUpParties.First(), GetSamlUpLogoutRequest(party, sessionId, idTokenClaims)));

            default:
                throw new NotSupportedException($"Party type '{type}' not supported.");
            }
        }
Example #9
0
        public async Task <IActionResult> SpMetadataAsync(string partyId)
        {
            logger.ScopeTrace(() => "Up, SP Metadata request.");
            logger.SetScopeProperty(Constants.Logs.UpPartyId, partyId);
            var party = RouteBinding.UpParty != null ? await tenantRepository.GetAsync <SamlUpParty>(partyId) : null;

            var signMetadata = party != null ? party.SignMetadata : false;

            var samlConfig = await saml2ConfigurationLogic.GetSamlUpConfigAsync(party, includeSigningAndDecryptionCertificate : signMetadata, includeSignatureValidationCertificates : false);

            var acsDestination          = new Uri(UrlCombine.Combine(HttpContext.GetHostWithTenantAndTrack(), RouteBinding.PartyNameAndBinding, Constants.Routes.SamlController, Constants.Endpoints.SamlAcs));
            var singleLogoutDestination = new Uri(UrlCombine.Combine(HttpContext.GetHostWithTenantAndTrack(), RouteBinding.PartyNameAndBinding, Constants.Routes.SamlController, Constants.Endpoints.SamlSingleLogout));

            var entityDescriptor = new EntityDescriptor(samlConfig, signMetadata);

            if (party != null)
            {
                entityDescriptor.ValidUntil = new TimeSpan(0, 0, settings.SamlMetadataLifetime).Days;
            }

            var trackCertificates = GetTrackCertificates();

            entityDescriptor.SPSsoDescriptor = new SPSsoDescriptor
            {
                //AuthnRequestsSigned = true,
                //WantAssertionsSigned = true,
                SigningCertificates       = trackCertificates,
                AssertionConsumerServices = new AssertionConsumerService[]
                {
                    new AssertionConsumerService {
                        Binding = ToSamleBindingUri(party?.AuthnBinding?.ResponseBinding), Location = acsDestination
                    },
                },
            };
            entityDescriptor.SPSsoDescriptor.SingleLogoutServices = new SingleLogoutService[]
            {
                new SingleLogoutService {
                    Binding = ToSamleBindingUri(party?.LogoutBinding?.ResponseBinding), Location = singleLogoutDestination
                },
            };

            if (party?.MetadataIncludeEncryptionCertificates == true)
            {
                entityDescriptor.SPSsoDescriptor.EncryptionCertificates = trackCertificates;
                entityDescriptor.SPSsoDescriptor.SetDefaultEncryptionMethods();
            }

            if (party?.MetadataNameIdFormats?.Count > 0)
            {
                entityDescriptor.SPSsoDescriptor.NameIDFormats = party.MetadataNameIdFormats.Select(nf => new Uri(nf));
            }

            if (party?.MetadataAttributeConsumingServices?.Count() > 0)
            {
                var attributeConsumingServices = new List <AttributeConsumingService>();
                foreach (var aItem in party.MetadataAttributeConsumingServices)
                {
                    var attributeConsumingService = new AttributeConsumingService {
                        ServiceName = new ServiceName(aItem.ServiceName.Name, aItem.ServiceName.Lang)
                    };
                    attributeConsumingService.RequestedAttributes = aItem.RequestedAttributes.Select(ra => string.IsNullOrEmpty(ra.NameFormat) ? new RequestedAttribute(ra.Name, ra.IsRequired) : new RequestedAttribute(ra.Name, ra.IsRequired, ra.NameFormat));
                    attributeConsumingServices.Add(attributeConsumingService);
                }
                entityDescriptor.SPSsoDescriptor.AttributeConsumingServices = attributeConsumingServices;
            }

            if (party?.MetadataContactPersons?.Count() > 0)
            {
                entityDescriptor.ContactPersons = GetContactPersons(party.MetadataContactPersons);
            }

            return(new Saml2Metadata(entityDescriptor).CreateMetadata().ToActionResult());
        }
        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());
        }
Example #11
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());
        }