コード例 #1
0
        private async Task <IActionResult> SingleLogoutRequestAsync(SamlUpParty party, SamlUpSequenceData sequenceData)
        {
            var session = await sessionUpPartyLogic.DeleteSessionAsync(party);

            await oauthRefreshTokenGrantLogic.DeleteRefreshTokenGrantsAsync(session.SessionId);

            if (party.DisableSingleLogout)
            {
                var samlConfig = await saml2ConfigurationLogic.GetSamlUpConfigAsync(party, includeSigningAndDecryptionCertificate : true);

                return(await SingleLogoutResponseAsync(party, samlConfig, sequenceData.Id, sequenceData.RelayState));
            }
            else
            {
                (var doSingleLogout, var singleLogoutSequenceData) = await singleLogoutDownLogic.InitializeSingleLogoutAsync(new UpPartyLink { Name = party.Name, Type = party.Type }, null, session.DownPartyLinks, session.Claims);

                if (doSingleLogout)
                {
                    return(await singleLogoutDownLogic.StartSingleLogoutAsync(singleLogoutSequenceData));
                }
                else
                {
                    var samlConfig = await saml2ConfigurationLogic.GetSamlUpConfigAsync(party, includeSigningAndDecryptionCertificate : true);

                    return(await SingleLogoutResponseAsync(party, samlConfig, sequenceData.Id, sequenceData.RelayState));
                }
            }
        }
コード例 #2
0
        public async Task <ActionResult <Api.SamlUpParty> > PostSamlUpPartyReadMetadata([FromBody] Api.SamlReadMetadataRequest samlReadMetadataRequest)
        {
            if (!await ModelState.TryValidateObjectAsync(samlReadMetadataRequest))
            {
                return(BadRequest(ModelState));
            }

            try
            {
                var samlUpParty = new SamlUpParty {
                    AuthnBinding = new SamlBinding()
                };
                switch (samlReadMetadataRequest.Type)
                {
                case Api.SamlReadMetadataType.Url:
                    samlUpParty.MetadataUrl = samlReadMetadataRequest.Metadata;
                    await samlMetadataReadLogic.PopulateModelAsync(samlUpParty);

                    break;

                case Api.SamlReadMetadataType.Xml:
                    await samlMetadataReadLogic.PopulateModelAsync(samlUpParty, samlReadMetadataRequest.Metadata);

                    break;

                default:
                    throw new NotSupportedException();
                }
                return(Ok(mapper.Map <Api.SamlUpParty>(samlUpParty)));
            }
            catch (Exception ex)
            {
                throw new ValidationException("Unable to read SAML 2.0 metadata.", ex);
            }
        }
コード例 #3
0
ファイル: SamlAuthnUpLogic.cs プロジェクト: ITfoxtec/FoxIDs
        private IEnumerable <Claim> ValidateClaims(SamlUpParty party, IEnumerable <Claim> claims)
        {
            var acceptAllClaims = party.Claims?.Where(c => c == "*")?.Count() > 0;

            if (!acceptAllClaims)
            {
                var acceptedClaims = Constants.DefaultClaims.SamlClaims.ConcatOnce(party.Claims);
                claims = claims.Where(c => acceptedClaims.Any(ic => ic == c.Type));
            }
            foreach (var claim in claims)
            {
                if (claim.Type?.Length > Constants.Models.Claim.SamlTypeLength)
                {
                    throw new SamlRequestException($"Claim '{claim.Type.Substring(0, Constants.Models.Claim.SamlTypeLength)}' is too long, maximum length of '{Constants.Models.Claim.SamlTypeLength}'.")
                          {
                              RouteBinding = RouteBinding, Status = Saml2StatusCodes.Responder
                          };
                }

                if (claim.Value?.Length > Constants.Models.Claim.ValueLength)
                {
                    throw new SamlRequestException($"Claim '{claim.Type}' value is too long, maximum length of '{Constants.Models.Claim.ValueLength}'.")
                          {
                              RouteBinding = RouteBinding, Status = Saml2StatusCodes.Responder
                          };
                }
            }
            return(claims);
        }
コード例 #4
0
        private async Task CreateAspNetCoreSamlIdPSampleUpPartyAsync()
        {
            Func <string, Task> getAction = async(name) =>
            {
                _ = await foxIDsApiClient.GetSamlUpPartyAsync(name);
            };

            Func <string, Task> postAction = async(name) =>
            {
                var baseUrl = "https://localhost:44342";

                var samlUpParty = new SamlUpParty
                {
                    Name   = name,
                    Issuer = "urn:itfoxtec:idservice:samples:aspnetcoresamlidpsample",
                    Keys   = new[] { GetSamlCertificateKey("AspNetCoreSamlIdPSample-test-sign-cert.crt") },
                    //SignatureAlgorithm = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
                    //CertificateValidationMode = X509CertificateValidationMode.None,
                    //RevocationMode = X509RevocationMode.NoCheck,
                    AuthnRequestBinding   = SamlBindingTypes.Redirect,
                    AuthnResponseBinding  = SamlBindingTypes.Post,
                    AuthnUrl              = UrlCombine.Combine(baseUrl, "saml/login"),
                    LogoutRequestBinding  = SamlBindingTypes.Post,
                    LogoutResponseBinding = SamlBindingTypes.Post,
                    LogoutUrl             = UrlCombine.Combine(baseUrl, "saml/logout"),
                    Claims = new string[] { ClaimTypes.Email, ClaimTypes.Name, ClaimTypes.GivenName, ClaimTypes.Surname, ClaimTypes.Role }
                };

                await foxIDsApiClient.PostSamlUpPartyAsync(samlUpParty);
            };

            await CreateIfNotExistsAsync(aspNetCoreSamlIdPSampleUpPartyName, getAction, postAction);
        }
コード例 #5
0
        public Saml2Configuration GetSamlUpConfig(SamlUpParty party, bool includeSigningCertificate = false)
        {
            var samlConfig = new Saml2Configuration();

            samlConfig.AllowedIssuer = party.Issuer;

            samlConfig.Issuer = !party.SpIssuer.IsNullOrEmpty() ? party.SpIssuer : trackIssuerLogic.GetIssuer();
            samlConfig.AllowedAudienceUris.Add(samlConfig.Issuer);

            samlConfig.SingleSignOnDestination = new Uri(party.AuthnUrl);
            if (!party.LogoutUrl.IsNullOrEmpty())
            {
                samlConfig.SingleLogoutDestination = new Uri(party.LogoutUrl);
            }

            foreach (var key in party.Keys)
            {
                samlConfig.SignatureValidationCertificates.Add(key.ToSaml2X509Certificate());
            }

            if (includeSigningCertificate)
            {
                samlConfig.SigningCertificate = trackKeyLogic.GetPrimarySaml2X509Certificate(RouteBinding.Key);
            }
            samlConfig.SignatureAlgorithm = party.SignatureAlgorithm;

            samlConfig.CertificateValidationMode = party.CertificateValidationMode;
            samlConfig.RevocationMode            = party.RevocationMode;

            return(samlConfig);
        }
コード例 #6
0
 private void ValidatePartyLogoutSupport(SamlUpParty party)
 {
     if (party.LogoutBinding == null || party.LogoutUrl.IsNullOrEmpty())
     {
         throw new EndpointException("Logout not configured.")
               {
                   RouteBinding = RouteBinding
               };
     }
 }
コード例 #7
0
        public async Task <FoxIDsSaml2Configuration> GetSamlUpConfigAsync(SamlUpParty party, bool includeSigningAndDecryptionCertificate = false, bool includeSignatureValidationCertificates = true)
        {
            var samlConfig = new FoxIDsSaml2Configuration();

            if (party != null)
            {
                samlConfig.AllowedIssuer = party.Issuer;
            }

            samlConfig.Issuer = !string.IsNullOrEmpty(party?.SpIssuer) ? party.SpIssuer : trackIssuerLogic.GetIssuer();
            samlConfig.AllowedAudienceUris.Add(samlConfig.Issuer);

            if (party != null)
            {
                samlConfig.SingleSignOnDestination = new Uri(party.AuthnUrl);
                if (!string.IsNullOrEmpty(party?.LogoutUrl))
                {
                    samlConfig.SingleLogoutDestination = new Uri(party.LogoutUrl);
                }

                if (includeSignatureValidationCertificates)
                {
                    var partyCertificates = party.Keys.ToSaml2X509Certificates();
                    foreach (var partyCertificate in partyCertificates)
                    {
                        if (partyCertificate.IsValidLocalTime())
                        {
                            samlConfig.SignatureValidationCertificates.Add(partyCertificate);
                        }
                        else
                        {
                            samlConfig.InvalidSignatureValidationCertificates.Add(partyCertificate);
                        }
                    }
                }
            }

            if (includeSigningAndDecryptionCertificate)
            {
                samlConfig.SigningCertificate = samlConfig.DecryptionCertificate = await trackKeyLogic.GetPrimarySaml2X509CertificateAsync(RouteBinding.Key);

                samlConfig.SecondaryDecryptionCertificate = trackKeyLogic.GetSecondarySaml2X509Certificate(RouteBinding.Key);
            }
            if (party != null)
            {
                samlConfig.SignatureAlgorithm = party.SignatureAlgorithm;
                samlConfig.SignAuthnRequest   = party.SignAuthnRequest;

                samlConfig.CertificateValidationMode = party.CertificateValidationMode;
                samlConfig.RevocationMode            = party.RevocationMode;
            }

            return(samlConfig);
        }
コード例 #8
0
        public async Task PopulateModelAsync(SamlUpParty party, string metadataXml)
        {
            if (metadataXml?.Length > Constants.Models.SamlParty.MetadataXmlSize)
            {
                throw new Exception($"Metadata XML must be a string with a maximum length of '{Constants.Models.SamlParty.MetadataXmlSize}'.");
            }

            var entityDescriptor = new EntityDescriptor();

            entityDescriptor.ReadIdPSsoDescriptor(metadataXml);
            await PopulateModelInternalAsync(party, entityDescriptor);
        }
コード例 #9
0
ファイル: SamlLogoutUpLogic.cs プロジェクト: lulzzz/FoxIDs
        private async Task <IActionResult> SingleLogoutRequestAsync <T>(SamlUpParty party, Saml2Binding <T> binding)
        {
            var samlConfig = saml2ConfigurationLogic.GetSamlUpConfig(party);

            var saml2LogoutRequest = new Saml2LogoutRequest(samlConfig);

            binding.ReadSamlRequest(HttpContext.Request.ToGenericHttpRequest(), saml2LogoutRequest);

            try
            {
                logger.ScopeTrace($"SAML Single Logout request '{saml2LogoutRequest.XmlDocument.OuterXml}'.");
                logger.ScopeTrace("Up, SAML Single Logout request.", triggerEvent: true);

                binding.Unbind(HttpContext.Request.ToGenericHttpRequest(), saml2LogoutRequest);
                logger.ScopeTrace("Up, Successful SAML Single Logout request.", triggerEvent: true);

                var session = await sessionUpPartyLogic.DeleteSessionAsync();

                await oauthRefreshTokenGrantLogic.DeleteRefreshTokenGrantsAsync(session.SessionId);

                await sequenceLogic.SaveSequenceDataAsync(new SamlUpSequenceData
                {
                    ExternalInitiatedSingleLogout = true,
                    Id         = saml2LogoutRequest.IdAsString,
                    UpPartyId  = party.Id,
                    RelayState = binding.RelayState,
                    SessionId  = saml2LogoutRequest.SessionIndex
                });

                if (party.DisableSingleLogout)
                {
                    return(await SingleLogoutResponseAsync(party, samlConfig, saml2LogoutRequest.Id.Value, binding.RelayState));
                }
                else
                {
                    (var doSingleLogout, var singleLogoutSequenceData) = await singleLogoutDownLogic.InitializeSingleLogoutAsync(new UpPartyLink { Name = party.Name, Type = party.Type }, null, session.DownPartyLinks, session.Claims);

                    if (doSingleLogout)
                    {
                        return(await singleLogoutDownLogic.StartSingleLogoutAsync(singleLogoutSequenceData));
                    }
                    else
                    {
                        return(await SingleLogoutResponseAsync(party, samlConfig, saml2LogoutRequest.Id.Value, binding.RelayState));
                    }
                }
            }
            catch (SamlRequestException ex)
            {
                logger.Error(ex);
                return(await SingleLogoutResponseAsync(party, samlConfig, saml2LogoutRequest.Id.Value, binding.RelayState, ex.Status));
            }
        }
コード例 #10
0
        private async Task PopulateModelInternalAsync(SamlUpParty party, EntityDescriptor entityDescriptor)
        {
            if (entityDescriptor.IdPSsoDescriptor != null)
            {
                party.LastUpdated = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
                party.Issuer      = entityDescriptor.EntityId;
                var singleSignOnServices = entityDescriptor.IdPSsoDescriptor.SingleSignOnServices.FirstOrDefault();
                if (singleSignOnServices == null)
                {
                    throw new Exception("IdPSsoDescriptor SingleSignOnServices is empty.");
                }

                party.AuthnUrl = singleSignOnServices.Location?.OriginalString;
                party.AuthnBinding.RequestBinding = GetSamlBindingTypes(singleSignOnServices.Binding?.OriginalString);

                var singleLogoutDestination = GetSingleLogoutServices(entityDescriptor.IdPSsoDescriptor.SingleLogoutServices);
                if (singleLogoutDestination != null)
                {
                    party.LogoutUrl = singleLogoutDestination.Location?.OriginalString;
                    var singleLogoutResponseLocation = singleLogoutDestination.ResponseLocation?.OriginalString;
                    if (!string.IsNullOrEmpty(singleLogoutResponseLocation))
                    {
                        party.SingleLogoutResponseUrl = singleLogoutResponseLocation;
                    }
                    if (party.LogoutBinding == null)
                    {
                        party.LogoutBinding = new SamlBinding {
                            ResponseBinding = SamlBindingTypes.Post
                        };
                    }
                    party.LogoutBinding.RequestBinding = GetSamlBindingTypes(singleLogoutDestination.Binding?.OriginalString);
                }

                if (entityDescriptor.IdPSsoDescriptor.SigningCertificates?.Count() > 0)
                {
                    party.Keys = await Task.FromResult(entityDescriptor.IdPSsoDescriptor.SigningCertificates.Select(c => c.ToFTJsonWebKey()).ToList());
                }
                else
                {
                    party.Keys = null;
                }

                if (entityDescriptor.IdPSsoDescriptor.WantAuthnRequestsSigned.HasValue)
                {
                    party.SignAuthnRequest = entityDescriptor.IdPSsoDescriptor.WantAuthnRequestsSigned.Value;
                }
            }
            else
            {
                throw new Exception("IdPSsoDescriptor not loaded from metadata.");
            }
        }
コード例 #11
0
        private async Task <IActionResult> SingleLogoutRequestAsync <T>(SamlUpParty party, Saml2Binding <T> binding)
        {
            var samlConfig = await saml2ConfigurationLogic.GetSamlUpConfigAsync(party);

            var saml2LogoutRequest = new Saml2LogoutRequest(samlConfig);

            binding.ReadSamlRequest(HttpContext.Request.ToGenericHttpRequest(), saml2LogoutRequest);

            try
            {
                logger.ScopeTrace(() => $"SAML Single Logout request '{saml2LogoutRequest.XmlDocument.OuterXml}'.", traceType: TraceTypes.Message);
                logger.ScopeTrace(() => "Up, SAML Single Logout request.", triggerEvent: true);

                try
                {
                    binding.Unbind(HttpContext.Request.ToGenericHttpRequest(), saml2LogoutRequest);
                    logger.ScopeTrace(() => "Up, Successful SAML Single Logout request.", triggerEvent: true);
                }
                catch (Exception ex)
                {
                    var isex = saml2ConfigurationLogic.GetInvalidSignatureValidationCertificateException(samlConfig, ex);
                    if (isex != null)
                    {
                        throw isex;
                    }
                    throw;
                }

                var sequenceData = await sequenceLogic.SaveSequenceDataAsync(new SamlUpSequenceData
                {
                    ExternalInitiatedSingleLogout = true,
                    Id         = saml2LogoutRequest.IdAsString,
                    UpPartyId  = party.Id,
                    RelayState = binding.RelayState,
                    SessionId  = saml2LogoutRequest.SessionIndex
                });

                if (binding is Saml2Binding <Saml2PostBinding> )
                {
                    return(HttpContext.GetUpPartyUrl(party.Name, Constants.Routes.SamlController, Constants.Endpoints.UpJump.SingleLogoutRequestJump, includeSequence: true, partyBindingPattern: party.PartyBindingPattern).ToRedirectResult());
                }
                else
                {
                    return(await SingleLogoutRequestAsync(party, sequenceData));
                }
            }
            catch (SamlRequestException ex)
            {
                logger.Error(ex);
                return(await SingleLogoutResponseAsync(party, samlConfig, saml2LogoutRequest.Id.Value, binding.RelayState, ex.Status));
            }
        }
コード例 #12
0
ファイル: SamlAuthnUpLogic.cs プロジェクト: ITfoxtec/FoxIDs
        private async Task <IActionResult> AuthnRequestAsync <T>(SamlUpParty party, Saml2Binding <T> binding, SamlUpSequenceData samlUpSequenceData)
        {
            var samlConfig = await saml2ConfigurationLogic.GetSamlUpConfigAsync(party, includeSigningAndDecryptionCertificate : true);

            binding.RelayState = await sequenceLogic.CreateExternalSequenceIdAsync();

            var saml2AuthnRequest = new Saml2AuthnRequest(samlConfig);

            switch (samlUpSequenceData.LoginAction)
            {
            case LoginAction.ReadSession:
                saml2AuthnRequest.IsPassive = true;
                break;

            case LoginAction.RequireLogin:
                saml2AuthnRequest.ForceAuthn = true;
                break;

            default:
                break;
            }

            if (party.AuthnContextClassReferences?.Count() > 0)
            {
                saml2AuthnRequest.RequestedAuthnContext = new RequestedAuthnContext
                {
                    Comparison           = party.AuthnContextComparison.HasValue ? (AuthnContextComparisonTypes)Enum.Parse(typeof(AuthnContextComparisonTypes), party.AuthnContextComparison.Value.ToString()) : null,
                    AuthnContextClassRef = party.AuthnContextClassReferences,
                };
            }

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

            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();
            }
        }
コード例 #13
0
        private async Task CreateAspNetCoreSamlIdPSampleUpPartyAsync()
        {
            Func <string, Task> getAction = async(name) =>
            {
                _ = await foxIDsApiClient.GetSamlUpPartyAsync(name);
            };

            Func <string, Task> postAction = async(name) =>
            {
                var baseUrl = "https://localhost:44342";

                var samlUpParty = new SamlUpParty
                {
                    Name   = name,
                    Issuer = "urn:itfoxtec:idservice:samples:aspnetcoresamlidpsample",
                    Keys   = new[]
                    {
                        new JsonWebKey
                        {
                            Kty = "RSA",
                            Kid = "27EB823D00B02FA7A02AA754146B6CFC60B8C301",
                            X5c = new[] { "MIICzzCCAbegAwIBAgIJANht5lyL71T0MA0GCSqGSIb3DQEBCwUAMBkxFzAVBgNVBAMTDnRlc3Qtc2lnbi1jZXJ0MB4XDTE4MTAxMTE1MDEyMVoXDTE5MTAxMjE1MDEyMVowGTEXMBUGA1UEAxMOdGVzdC1zaWduLWNlcnQwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUf6b4mtamR7DvTdtz6fdtEe+aXHpzXqvTrjf3SbN5Hol+kAvrIGVXcnJJSfO6N9yC/s8fPE4crVJKwceGkeykzt/j0UHRafmX7e7zzCPO8nd8pVSwZtflogNVdYbrIPTIHLP/eOrPt4Im2PHU0Q561frZjIDgqaoGmtpTLof/0z3GoD52hesZyeE3mW9Q0/+TngLne52rmDe9gmebtmckM7wJw9DXbaJhI24KZPn25PRYnPJMuyBh2EFjJ6qjIAQodpaMstdH6eGJyTan9J/yI6yPhYZ3jl4UngwZ7OpSiGB7m335SYIpPRGxZSdN/tGGdVPV1TIyBU6QFD5mn259AgMBAAGjGjAYMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgXgMA0GCSqGSIb3DQEBCwUAA4IBAQCCYJoiq4sVqTyJ5md4VJIvT3Ezoo6MUDxPmC+bcdT+4j0rYPJr69Fv7celEcS7NEnDK3JQXU2bJ1HAAExBz53bqZphlFnuDFQcJU2lYGaOamDUN/v2aEM/g/Zrlbs4/V4WsCETUkcq7FwmtVia58AZSOtBEqpS7OpdEq4WUmWPRqpjDn+Ne1n921qIKMDtczqOCGc/BREbFUjy49gY/+a57WUxXPhL0gWrGHBwSLIJHp/m9sG7wFA6a2wnvgycrAMYFZ50iGe6IcSzktRdQXd5lTeVtl4JgftwIplIqWyuTYoHwTX+xo2qMSMCF38w31j6BASAmXJniKWeK8aeQ9o7" },
                            X5t = "J-uCPQCwL6egKqdUFGts_GC4wwE",
                            N   = "1H-m-JrWpkew703bc-n3bRHvmlx6c16r064390mzeR6JfpAL6yBlV3JySUnzujfcgv7PHzxOHK1SSsHHhpHspM7f49FB0Wn5l-3u88wjzvJ3fKVUsGbX5aIDVXWG6yD0yByz_3jqz7eCJtjx1NEOetX62YyA4KmqBpraUy6H_9M9xqA-doXrGcnhN5lvUNP_k54C53udq5g3vYJnm7ZnJDO8CcPQ122iYSNuCmT59uT0WJzyTLsgYdhBYyeqoyAEKHaWjLLXR-nhick2p_Sf8iOsj4WGd45eFJ4MGezqUohge5t9-UmCKT0RsWUnTf7RhnVT1dUyMgVOkBQ-Zp9ufQ",
                            E   = "AQAB"
                        }
                    },
                    //SignatureAlgorithm = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
                    //CertificateValidationMode = X509CertificateValidationMode.None,
                    //RevocationMode = X509RevocationMode.NoCheck,
                    AuthnBinding = new SamlBinding {
                        RequestBinding = SamlBindingTypes.Redirect, ResponseBinding = SamlBindingTypes.Post
                    },
                    AuthnUrl      = UrlCombine.Combine(baseUrl, "saml/login"),
                    LogoutBinding = new SamlBinding {
                        RequestBinding = SamlBindingTypes.Post, ResponseBinding = SamlBindingTypes.Post
                    },
                    LogoutUrl = UrlCombine.Combine(baseUrl, "saml/logout"),
                    Claims    = new string[] { ClaimTypes.Email, ClaimTypes.Name, ClaimTypes.GivenName, ClaimTypes.Surname, ClaimTypes.Role }
                };

                await foxIDsApiClient.PostSamlUpPartyAsync(samlUpParty);
            };

            await CreateIfNotExistsAsync(aspNetCoreSamlIdPSampleUpPartyName, getAction, postAction);
        }
コード例 #14
0
        private async Task <IActionResult> LogoutAsync <T>(SamlUpParty party, Saml2Binding <T> binding, LogoutRequest logoutRequest)
        {
            var samlConfig = saml2ConfigurationLogic.GetSamlUpConfig(party, includeSigningCertificate: true);
            await formActionLogic.AddFormActionByUrlAsync(samlConfig.SingleLogoutDestination.OriginalString);

            binding.RelayState = SequenceString;

            var saml2LogoutRequest = new Saml2LogoutRequest(samlConfig);

            saml2LogoutRequest.SessionIndex = logoutRequest.SessionId;

            var nameID       = logoutRequest.Claims?.Where(c => c.Type == Saml2ClaimTypes.NameId).Select(c => c.Value).FirstOrDefault();
            var nameIdFormat = logoutRequest.Claims?.Where(c => c.Type == Saml2ClaimTypes.NameIdFormat).Select(c => c.Value).FirstOrDefault();

            if (!nameID.IsNullOrEmpty())
            {
                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}'.");
            logger.ScopeTrace($"Logout url '{samlConfig.SingleLogoutDestination?.OriginalString}'.");
            logger.ScopeTrace("Up, SAML Logout request.", triggerEvent: true);

            if (binding is Saml2Binding <Saml2RedirectBinding> )
            {
                return(await Task.FromResult((binding as Saml2RedirectBinding).ToActionResult()));
            }
            if (binding is Saml2Binding <Saml2PostBinding> )
            {
                return(await Task.FromResult((binding as Saml2PostBinding).ToActionResult()));
            }
            else
            {
                throw new NotSupportedException();
            }
        }
コード例 #15
0
        private async Task <IActionResult> SingleLogoutResponseAsync(SamlUpParty party, Saml2Configuration samlConfig, string inResponseTo, string relayState, Saml2StatusCodes status = Saml2StatusCodes.Success, string sessionIndex = null)
        {
            logger.ScopeTrace(() => $"Down, SAML Single Logout response{(status != Saml2StatusCodes.Success ? " error" : string.Empty)}, Status code '{status}'.");

            var binding = party.LogoutBinding.ResponseBinding;

            logger.ScopeTrace(() => $"Binding '{binding}'");
            switch (binding)
            {
            case SamlBindingTypes.Redirect:
                return(await LogoutResponseAsync(samlConfig, inResponseTo, relayState, GetSingleLogoutResponseUrl(party), new Saml2RedirectBinding(), status, sessionIndex));

            case SamlBindingTypes.Post:
                return(await LogoutResponseAsync(samlConfig, inResponseTo, relayState, GetSingleLogoutResponseUrl(party), new Saml2PostBinding(), status, sessionIndex));

            default:
                throw new NotSupportedException($"SAML binding '{binding}' not supported.");
            }
        }
コード例 #16
0
        private async Task <IActionResult> LogoutResponseAsync <T>(SamlUpParty party, Saml2Binding <T> binding)
        {
            var samlConfig = saml2ConfigurationLogic.GetSamlUpConfig(party);

            var saml2LogoutResponse = new Saml2LogoutResponse(samlConfig);

            binding.ReadSamlResponse(HttpContext.Request.ToGenericHttpRequest(), saml2LogoutResponse);

            await sequenceLogic.ValidateSequenceAsync(binding.RelayState);

            var sequenceData = await sequenceLogic.GetSequenceDataAsync <SamlUpSequenceData>();

            try
            {
                logger.ScopeTrace($"SAML Logout response '{saml2LogoutResponse.XmlDocument.OuterXml}'.");
                logger.SetScopeProperty("status", saml2LogoutResponse.Status.ToString());
                logger.ScopeTrace("Up, SAML Logout response.", triggerEvent: true);

                if (saml2LogoutResponse.Status != Saml2StatusCodes.Success)
                {
                    throw new SamlRequestException("Unsuccessful Logout response.")
                          {
                              RouteBinding = RouteBinding, Status = saml2LogoutResponse.Status
                          };
                }

                binding.Unbind(HttpContext.Request.ToGenericHttpRequest(), saml2LogoutResponse);
                logger.ScopeTrace("Up, Successful SAML Logout response.", triggerEvent: true);

                return(await LogoutResponseDownAsync(sequenceData, saml2LogoutResponse.Status, saml2LogoutResponse.SessionIndex));
            }
            catch (SamlRequestException ex)
            {
                logger.Error(ex);
                return(await LogoutResponseDownAsync(sequenceData, ex.Status));
            }
            catch (Exception ex)
            {
                logger.Error(ex);
                return(await LogoutResponseDownAsync(sequenceData, Saml2StatusCodes.Responder));
            }
        }
コード例 #17
0
ファイル: SamlAuthnUpLogic.cs プロジェクト: lulzzz/FoxIDs
        private async Task <IActionResult> AuthnRequestAsync <T>(SamlUpParty party, Saml2Binding <T> binding, SamlUpSequenceData samlUpSequenceData)
        {
            var samlConfig = saml2ConfigurationLogic.GetSamlUpConfig(party);

            binding.RelayState = SequenceString;
            var saml2AuthnRequest = new Saml2AuthnRequest(samlConfig);

            switch (samlUpSequenceData.LoginAction)
            {
            case LoginAction.ReadSession:
                saml2AuthnRequest.IsPassive = true;
                break;

            case LoginAction.RequireLogin:
                saml2AuthnRequest.ForceAuthn = true;
                break;

            default:
                break;
            }

            binding.Bind(saml2AuthnRequest);
            logger.ScopeTrace($"SAML Authn request '{saml2AuthnRequest.XmlDocument.OuterXml}'.");
            logger.ScopeTrace($"Authn URL '{samlConfig.SingleSignOnDestination?.OriginalString}'.");
            logger.ScopeTrace("Up, Sending SAML Authn request.", triggerEvent: true);

            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();
            }
        }
コード例 #18
0
        public Saml2Configuration GetSamlUpConfig(SamlUpParty party, bool includeSigningCertificate = false)
        {
            var samlConfig = new Saml2Configuration();

            if (!party.IdSIssuer.IsNullOrEmpty())
            {
                samlConfig.Issuer = party.IdSIssuer;
            }
            else
            {
                samlConfig.Issuer = UrlCombine.Combine(HttpContext.GetHost(), RouteBinding.TenantName, RouteBinding.TrackName);
            }

            samlConfig.AllowedAudienceUris.Add(samlConfig.Issuer);

            samlConfig.SingleSignOnDestination = new Uri(party.AuthnUrl);
            if (!party.LogoutUrl.IsNullOrEmpty())
            {
                samlConfig.SingleLogoutDestination = new Uri(party.LogoutUrl);
            }

            foreach (var key in party.Keys)
            {
                samlConfig.SignatureValidationCertificates.Add(key.ToSaml2X509Certificate());
            }

            if (includeSigningCertificate)
            {
                samlConfig.SigningCertificate = trackKeyLogic.GetSaml2X509Certificate(RouteBinding.PrimaryKey);
            }
            samlConfig.SignatureAlgorithm = party.SignatureAlgorithm;

            samlConfig.CertificateValidationMode = party.CertificateValidationMode;
            samlConfig.RevocationMode            = party.RevocationMode;

            return(samlConfig);
        }
コード例 #19
0
        private IEnumerable <Claim> ValidateClaims(SamlUpParty party, IEnumerable <Claim> claims)
        {
            IEnumerable <string> acceptedClaims = Constants.DefaultClaims.SamlClaims.ConcatOnce(party.Claims);

            claims = claims.Where(c => acceptedClaims.Any(ic => ic == c.Type));
            foreach (var claim in claims)
            {
                if (claim.Type?.Count() > Constants.Models.SamlParty.ClaimLength)
                {
                    throw new SamlRequestException($"Claim '{claim.Type.Substring(0, Constants.Models.SamlParty.ClaimLength)}' is too long.")
                          {
                              RouteBinding = RouteBinding, Status = Saml2StatusCodes.Responder
                          };
                }
                if (claim.Value?.Count() > Constants.Models.SamlParty.ClaimValueLength)
                {
                    throw new SamlRequestException($"Claim value '{claim.Value.Substring(0, Constants.Models.SamlParty.ClaimValueLength)}' is too long.")
                          {
                              RouteBinding = RouteBinding, Status = Saml2StatusCodes.Responder
                          };
                }
            }
            return(claims);
        }
コード例 #20
0
        public async Task <bool> PopulateModelAsync(ModelStateDictionary modelState, SamlUpParty mp)
        {
            var isValid = true;

            try
            {
                if (mp.UpdateState != PartyUpdateStates.Manual)
                {
                    await samlMetadataReadLogic.PopulateModelAsync(mp);

                    if (mp.UpdateState == PartyUpdateStates.AutomaticStopped)
                    {
                        mp.UpdateState = PartyUpdateStates.Automatic;
                    }
                }
            }
            catch (Exception ex)
            {
                isValid = false;
                logger.Warning(ex);
                modelState.TryAddModelError(nameof(mp.MetadataUrl).ToCamelCase(), ex.GetAllMessagesJoined());
            }
            return(isValid);
        }
コード例 #21
0
 private string GetSingleLogoutResponseUrl(SamlUpParty party) => party.SingleLogoutResponseUrl.IsNullOrEmpty() ? party.LogoutUrl : party.SingleLogoutResponseUrl;
コード例 #22
0
        public async Task CheckMetadataAndUpdateUpPartyAsync(SamlUpParty party)
        {
            if (party.UpdateState != PartyUpdateStates.Automatic)
            {
                return;
            }

            var lastUpdated = DateTimeOffset.FromUnixTimeSeconds(party.LastUpdated);

            if (lastUpdated.AddSeconds(party.MetadataUpdateRate.Value) >= DateTimeOffset.UtcNow)
            {
                return;
            }

            var db  = redisConnectionMultiplexer.GetDatabase();
            var key = UpdateUpPartyWaitPeriodKey(party.Id);

            if (await db.KeyExistsAsync(key))
            {
                logger.ScopeTrace(() => $"Up party '{party.Id}' not updated with SAML 2.0 metadata because another update is in progress.");
                return;
            }
            else
            {
                await db.StringSetAsync(key, true, TimeSpan.FromSeconds(settings.UpPartyUpdateWaitPeriod));
            }

            var failingUpdateCount = (long?)await db.StringGetAsync(FailingUpdateUpPartyCountKey(party.Id));

            if (failingUpdateCount.HasValue && failingUpdateCount.Value >= settings.UpPartyMaxFailingUpdate)
            {
                party.UpdateState = PartyUpdateStates.AutomaticStopped;
                await tenantRepository.SaveAsync(party);

                await db.KeyDeleteAsync(FailingUpdateUpPartyCountKey(party.Id));

                return;
            }

            try
            {
                try
                {
                    await samlMetadataReadLogic.PopulateModelAsync(party);
                }
                catch (Exception ex)
                {
                    throw new EndpointException("Failed to read SAML 2.0 metadata.", ex)
                          {
                              RouteBinding = RouteBinding
                          };
                }

                await tenantRepository.SaveAsync(party);

                logger.ScopeTrace(() => $"Up party '{party.Id}' updated by SAML 2.0 metadata.", triggerEvent: true);

                await db.KeyDeleteAsync(FailingUpdateUpPartyCountKey(party.Id));
            }
            catch (Exception ex)
            {
                await db.StringIncrementAsync(FailingUpdateUpPartyCountKey(party.Id));

                logger.Warning(ex);
            }
        }
コード例 #23
0
        public async Task PopulateModelAsync(SamlUpParty party)
        {
            var metadata = await ReadMetadataAsync(party.MetadataUrl);

            await PopulateModelAsync(party, metadata);
        }
コード例 #24
0
 public async Task UpdateSamlUpPartyAsync(SamlUpParty party) => await PutAsync(samlApiUri, party);
コード例 #25
0
 public async Task CreateSamlUpPartyAsync(SamlUpParty party) => await PostAsync(samlApiUri, party);
コード例 #26
0
        private async Task <IActionResult> AuthnResponseAsync <T>(SamlUpParty party, Saml2Binding <T> binding)
        {
            var request    = HttpContext.Request;
            var samlConfig = saml2ConfigurationLogic.GetSamlUpConfig(party);

            var saml2AuthnResponse = new Saml2AuthnResponse(samlConfig);

            binding.ReadSamlResponse(request.ToGenericHttpRequest(), saml2AuthnResponse);

            await sequenceLogic.ValidateSequenceAsync(binding.RelayState);

            var sequenceData = await sequenceLogic.GetSequenceDataAsync <SamlUpSequenceData>();

            try
            {
                logger.ScopeTrace($"SAML Authn response '{saml2AuthnResponse.XmlDocument.OuterXml}'.");
                logger.SetScopeProperty("status", saml2AuthnResponse.Status.ToString());
                logger.ScopeTrace("Up, SAML Authn response.", triggerEvent: true);

                if (saml2AuthnResponse.Status != Saml2StatusCodes.Success)
                {
                    throw new SamlRequestException("Unsuccessful Authn response.")
                          {
                              RouteBinding = RouteBinding, Status = saml2AuthnResponse.Status
                          };
                }

                binding.Unbind(request.ToGenericHttpRequest(), saml2AuthnResponse);
                logger.ScopeTrace("Up, Successful SAML Authn response.", triggerEvent: true);

                var claims = saml2AuthnResponse.ClaimsIdentity?.Claims;
                if (saml2AuthnResponse.ClaimsIdentity?.Claims?.Count() <= 0)
                {
                    throw new SamlRequestException("Empty claims collection.")
                          {
                              RouteBinding = RouteBinding, Status = Saml2StatusCodes.Responder
                          };
                }

                if (!claims.Any(c => c.Type == ClaimTypes.NameIdentifier))
                {
                    claims = AddNameIdClaim(claims);
                }

                claims = await claimTransformationsLogic.Transform(party.ClaimTransformations?.ConvertAll(t => (ClaimTransformation)t), claims);

                claims = ValidateClaims(party, claims);

                return(await AuthnResponseDownAsync(sequenceData, saml2AuthnResponse.Status, claims));
            }
            catch (SamlRequestException ex)
            {
                logger.Error(ex);
                return(await AuthnResponseDownAsync(sequenceData, ex.Status));
            }
            catch (Exception ex)
            {
                logger.Error(ex);
                return(await AuthnResponseDownAsync(sequenceData, Saml2StatusCodes.Responder));
            }
        }
コード例 #27
0
ファイル: SamlAuthnUpLogic.cs プロジェクト: lulzzz/FoxIDs
        private async Task <IActionResult> AuthnResponseAsync <T>(SamlUpParty party, Saml2Binding <T> binding)
        {
            var request    = HttpContext.Request;
            var samlConfig = saml2ConfigurationLogic.GetSamlUpConfig(party);

            var saml2AuthnResponse = new Saml2AuthnResponse(samlConfig);

            binding.ReadSamlResponse(request.ToGenericHttpRequest(), saml2AuthnResponse);
            if (binding.RelayState.IsNullOrEmpty())
            {
                throw new ArgumentNullException(nameof(binding.RelayState), binding.GetTypeName());
            }

            await sequenceLogic.ValidateSequenceAsync(binding.RelayState);

            var sequenceData = await sequenceLogic.GetSequenceDataAsync <SamlUpSequenceData>();

            try
            {
                logger.ScopeTrace($"SAML Authn response '{saml2AuthnResponse.XmlDocument.OuterXml}'.");
                logger.SetScopeProperty("upPartyStatus", saml2AuthnResponse.Status.ToString());
                logger.ScopeTrace("Up, SAML Authn response.", triggerEvent: true);

                if (saml2AuthnResponse.Status != Saml2StatusCodes.Success)
                {
                    throw new SamlRequestException("Unsuccessful Authn response.")
                          {
                              RouteBinding = RouteBinding, Status = saml2AuthnResponse.Status
                          };
                }

                binding.Unbind(request.ToGenericHttpRequest(), saml2AuthnResponse);
                logger.ScopeTrace("Up, Successful SAML Authn response.", triggerEvent: true);

                if (saml2AuthnResponse.ClaimsIdentity?.Claims?.Count() <= 0)
                {
                    throw new SamlRequestException("Empty claims collection.")
                          {
                              RouteBinding = RouteBinding, Status = Saml2StatusCodes.Responder
                          };
                }

                var claims      = new List <Claim>(saml2AuthnResponse.ClaimsIdentity.Claims.Where(c => c.Type != ClaimTypes.NameIdentifier));
                var nameIdClaim = GetNameIdClaim(party.Name, saml2AuthnResponse.ClaimsIdentity.Claims);
                if (nameIdClaim != null)
                {
                    claims.Add(nameIdClaim);
                }

                var externalSessionId = claims.FindFirstValue(c => c.Type == Saml2ClaimTypes.SessionIndex);
                externalSessionId.ValidateMaxLength(IdentityConstants.MessageLength.SessionIdMax, nameof(externalSessionId), "Session index claim");
                claims = claims.Where(c => c.Type != Saml2ClaimTypes.SessionIndex && c.Type != Constants.SamlClaimTypes.UpPary && c.Type != Constants.SamlClaimTypes.UpParyType).ToList();
                claims.AddClaim(Constants.SamlClaimTypes.UpPary, party.Name);
                claims.AddClaim(Constants.SamlClaimTypes.UpParyType, party.Type.ToString().ToLower());

                var transformedClaims = await claimTransformationsLogic.Transform(party.ClaimTransforms?.ConvertAll(t => (ClaimTransform)t), claims);

                var validClaims = ValidateClaims(party, transformedClaims);

                var jwtValidClaims = await claimsDownLogic.FromSamlToJwtClaimsAsync(validClaims);

                var sessionId = await sessionUpPartyLogic.CreateOrUpdateSessionAsync(party, party.DisableSingleLogout?null : sequenceData.DownPartyLink, jwtValidClaims, externalSessionId);

                if (!sessionId.IsNullOrEmpty())
                {
                    jwtValidClaims.AddClaim(JwtClaimTypes.SessionId, sessionId);
                }

                return(await AuthnResponseDownAsync(sequenceData, saml2AuthnResponse.Status, jwtValidClaims));
            }
            catch (StopSequenceException)
            {
                throw;
            }
            catch (SamlRequestException ex)
            {
                logger.Error(ex);
                return(await AuthnResponseDownAsync(sequenceData, ex.Status));
            }
            catch (Exception ex)
            {
                logger.Error(ex);
                return(await AuthnResponseDownAsync(sequenceData, Saml2StatusCodes.Responder));
            }
        }
コード例 #28
0
ファイル: SamlAuthnUpLogic.cs プロジェクト: ITfoxtec/FoxIDs
        private async Task <IActionResult> AuthnResponseAsync <T>(SamlUpParty party, Saml2Binding <T> binding)
        {
            var request    = HttpContext.Request;
            var samlConfig = await saml2ConfigurationLogic.GetSamlUpConfigAsync(party, includeSigningAndDecryptionCertificate : true);

            var saml2AuthnResponse = new Saml2AuthnResponse(samlConfig);

            try
            {
                binding.ReadSamlResponse(request.ToGenericHttpRequest(), saml2AuthnResponse);
            }
            catch (Exception ex)
            {
                if (samlConfig.SecondaryDecryptionCertificate != null && binding is Saml2PostBinding && ex.Source.Contains("cryptography", StringComparison.OrdinalIgnoreCase))
                {
                    samlConfig.DecryptionCertificate = samlConfig.SecondaryDecryptionCertificate;
                    saml2AuthnResponse = new Saml2AuthnResponse(samlConfig);
                    binding.ReadSamlResponse(request.ToGenericHttpRequest(), saml2AuthnResponse);
                    logger.ScopeTrace(() => $"SAML Authn response decrypted with secondary certificate.", traceType: TraceTypes.Message);
                }
                else
                {
                    throw;
                }
            }

            if (binding.RelayState.IsNullOrEmpty())
            {
                throw new ArgumentNullException(nameof(binding.RelayState), binding.GetTypeName());
            }

            await sequenceLogic.ValidateExternalSequenceIdAsync(binding.RelayState);

            var sequenceData = await sequenceLogic.GetSequenceDataAsync <SamlUpSequenceData>();

            try
            {
                logger.ScopeTrace(() => $"SAML Authn response '{saml2AuthnResponse.XmlDocument.OuterXml}'.", traceType: TraceTypes.Message);
                logger.SetScopeProperty(Constants.Logs.UpPartyStatus, saml2AuthnResponse.Status.ToString());
                logger.ScopeTrace(() => "Up, SAML Authn response.", triggerEvent: true);

                if (saml2AuthnResponse.Status != Saml2StatusCodes.Success)
                {
                    throw new SamlRequestException("Unsuccessful Authn response.")
                          {
                              RouteBinding = RouteBinding, Status = saml2AuthnResponse.Status
                          };
                }

                try
                {
                    binding.Unbind(request.ToGenericHttpRequest(), saml2AuthnResponse);
                    logger.ScopeTrace(() => "Up, Successful SAML Authn response.", triggerEvent: true);
                }
                catch (Exception ex)
                {
                    var isex = saml2ConfigurationLogic.GetInvalidSignatureValidationCertificateException(samlConfig, ex);
                    if (isex != null)
                    {
                        throw isex;
                    }
                    throw;
                }

                if (saml2AuthnResponse.ClaimsIdentity?.Claims?.Count() <= 0)
                {
                    throw new SamlRequestException("Empty claims collection.")
                          {
                              RouteBinding = RouteBinding, Status = Saml2StatusCodes.Responder
                          };
                }

                var claims      = new List <Claim>(saml2AuthnResponse.ClaimsIdentity.Claims.Where(c => c.Type != ClaimTypes.NameIdentifier));
                var nameIdClaim = GetNameIdClaim(party.Name, saml2AuthnResponse.ClaimsIdentity.Claims);
                if (nameIdClaim != null)
                {
                    claims.Add(nameIdClaim);
                }
                logger.ScopeTrace(() => $"Up, SAML Authn received SAML claims '{claims.ToFormattedString()}'", traceType: TraceTypes.Claim);

                var externalSessionId = claims.FindFirstValue(c => c.Type == Saml2ClaimTypes.SessionIndex);
                externalSessionId.ValidateMaxLength(IdentityConstants.MessageLength.SessionIdMax, nameof(externalSessionId), "Session index claim");
                claims = claims.Where(c => c.Type != Saml2ClaimTypes.SessionIndex && c.Type != Constants.SamlClaimTypes.UpParty && c.Type != Constants.SamlClaimTypes.UpPartyType).ToList();
                claims.AddClaim(Constants.SamlClaimTypes.UpParty, party.Name);
                claims.AddClaim(Constants.SamlClaimTypes.UpPartyType, party.Type.ToString().ToLower());

                var transformedClaims = await claimTransformLogic.Transform(party.ClaimTransforms?.ConvertAll(t => (ClaimTransform)t), claims);

                var validClaims = ValidateClaims(party, transformedClaims);
                logger.ScopeTrace(() => $"Up, SAML Authn output SAML claims '{validClaims.ToFormattedString()}'", traceType: TraceTypes.Claim);

                var jwtValidClaims = await claimsDownLogic.FromSamlToJwtClaimsAsync(validClaims);

                var sessionId = await sessionUpPartyLogic.CreateOrUpdateSessionAsync(party, party.DisableSingleLogout?null : sequenceData.DownPartyLink, jwtValidClaims, externalSessionId);

                if (!sessionId.IsNullOrEmpty())
                {
                    jwtValidClaims.AddClaim(JwtClaimTypes.SessionId, sessionId);
                }

                logger.ScopeTrace(() => $"Up, SAML Authn output JWT claims '{jwtValidClaims.ToFormattedString()}'", traceType: TraceTypes.Claim);
                return(await AuthnResponseDownAsync(sequenceData, saml2AuthnResponse.Status, jwtValidClaims));
            }
            catch (StopSequenceException)
            {
                throw;
            }
            catch (SamlRequestException ex)
            {
                logger.Error(ex);
                return(await AuthnResponseDownAsync(sequenceData, ex.Status));
            }
            catch (Exception ex)
            {
                logger.Error(ex);
                return(await AuthnResponseDownAsync(sequenceData, Saml2StatusCodes.Responder));
            }
        }
コード例 #29
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();
            }
        }
コード例 #30
0
        private async Task <IActionResult> LogoutResponseAsync <T>(SamlUpParty party, Saml2Binding <T> binding)
        {
            var samlConfig = await saml2ConfigurationLogic.GetSamlUpConfigAsync(party);

            var saml2LogoutResponse = new Saml2LogoutResponse(samlConfig);

            binding.ReadSamlResponse(HttpContext.Request.ToGenericHttpRequest(), saml2LogoutResponse);

            await sequenceLogic.ValidateExternalSequenceIdAsync(binding.RelayState);

            var sequenceData = await sequenceLogic.GetSequenceDataAsync <SamlUpSequenceData>(remove : party.DisableSingleLogout);

            try
            {
                logger.ScopeTrace(() => $"SAML Logout response '{saml2LogoutResponse.XmlDocument.OuterXml}'.", traceType: TraceTypes.Message);
                logger.SetScopeProperty(Constants.Logs.Status, saml2LogoutResponse.Status.ToString());
                logger.ScopeTrace(() => "Up, SAML Logout response.", triggerEvent: true);

                if (saml2LogoutResponse.Status != Saml2StatusCodes.Success)
                {
                    throw new SamlRequestException("Unsuccessful Logout response.")
                          {
                              RouteBinding = RouteBinding, Status = saml2LogoutResponse.Status
                          };
                }

                try
                {
                    binding.Unbind(HttpContext.Request.ToGenericHttpRequest(), saml2LogoutResponse);
                    logger.ScopeTrace(() => "Up, Successful SAML Logout response.", triggerEvent: true);
                }
                catch (Exception ex)
                {
                    var isex = saml2ConfigurationLogic.GetInvalidSignatureValidationCertificateException(samlConfig, ex);
                    if (isex != null)
                    {
                        throw isex;
                    }
                    throw;
                }

                if (party.DisableSingleLogout)
                {
                    return(await LogoutResponseDownAsync(sequenceData));
                }
                else
                {
                    (var doSingleLogout, var singleLogoutSequenceData) = await singleLogoutDownLogic.InitializeSingleLogoutAsync(new UpPartyLink { Name = party.Name, Type = party.Type }, sequenceData.DownPartyLink, sequenceData.SessionDownPartyLinks, sequenceData.SessionClaims);

                    if (doSingleLogout)
                    {
                        return(await singleLogoutDownLogic.StartSingleLogoutAsync(singleLogoutSequenceData));
                    }
                    else
                    {
                        await sequenceLogic.RemoveSequenceDataAsync <SamlUpSequenceData>();

                        return(await LogoutResponseDownAsync(sequenceData));
                    }
                }
            }
            catch (StopSequenceException)
            {
                throw;
            }
            catch (SamlRequestException ex)
            {
                logger.Error(ex);
                return(await LogoutResponseDownAsync(sequenceData, status : ex.Status));
            }
            catch (Exception ex)
            {
                logger.Error(ex);
                return(await LogoutResponseDownAsync(sequenceData, status : Saml2StatusCodes.Responder));
            }
        }