예제 #1
0
        private static CommandResult HandleResponse(UnbindResult unbindResult, StoredRequestState storedRequestState, IOptions options, Uri returnUrl)
        {
            var logoutResponse = Saml2LogoutResponse.FromXml(unbindResult.Data);
            var notificationHandledTheStatus = options.Notifications.ProcessSingleLogoutResponseStatus(logoutResponse, storedRequestState);

            if (!notificationHandledTheStatus)
            {
                var status = logoutResponse.Status;
                if (status != Saml2StatusCode.Success)
                {
                    throw new UnsuccessfulSamlOperationException(string.Format(CultureInfo.InvariantCulture,
                                                                               "Idp returned status \"{0}\", indicating that the single logout failed. The local session has been successfully terminated.",
                                                                               status));
                }
            }

            var commandResult = new CommandResult
            {
                HttpStatusCode = HttpStatusCode.SeeOther
            };

            if (!options.SPOptions.Compatibility.DisableLogoutStateCookie)
            {
                commandResult.ClearCookieName = StoredRequestState.CookieNameBase + unbindResult.RelayState;
            }
            commandResult.Location = storedRequestState?.ReturnUrl ?? returnUrl;

            options.SPOptions.Logger.WriteInformation("Received logout response " + logoutResponse.Id
                                                      + ", redirecting to " + commandResult.Location);

            return(commandResult);
        }
예제 #2
0
        private static void VerifyMessageIsSigned(UnbindResult unbindResult, IOptions options)
        {
            if (unbindResult.TrustLevel < TrustLevel.Signature)
            {
                var issuer = unbindResult.Data["Issuer", Saml2Namespaces.Saml2Name]?.InnerText;

                if (issuer == null)
                {
                    throw new InvalidSignatureException(
                              "There is no Issuer element in the message, so there is no way to know what certificate to use to validate the signature.");
                }

                var idp = options.IdentityProviders[new EntityId(issuer)];

                if (!unbindResult.Data.IsSignedByAny(
                        idp.SigningKeys,
                        options.SPOptions.ValidateCertificates,
                        options.SPOptions.MinIncomingSigningAlgorithm))
                {
                    throw new UnsuccessfulSamlOperationException(string.Format(CultureInfo.InvariantCulture,
                                                                               "Received a {0} from {1} that cannot be processed because it is not signed.",
                                                                               unbindResult.Data.LocalName,
                                                                               unbindResult.Data["Issuer", Saml2Namespaces.Saml2Name].InnerText));
                }
            }
        }
예제 #3
0
        private static CommandResult HandleRequest(UnbindResult unbindResult, HttpRequestData httpRequest, IOptions options)
        {
            var request = Saml2LogoutRequest.FromXml(unbindResult.Data);

            var idp = options.IdentityProviders[request.Issuer];

            if (options.SPOptions.SigningServiceCertificate == null)
            {
                throw new ConfigurationErrorsException(string.Format(CultureInfo.InvariantCulture,
                                                                     "Received a LogoutRequest from \"{0}\" but cannot reply because single logout responses " +
                                                                     "must be signed and there is no signing certificate configured. Looks like the idp is " +
                                                                     "configured for Single Logout despite Saml2 not exposing that functionality in the metadata.",
                                                                     request.Issuer.Id));
            }

            if (idp.SingleLogoutServiceResponseUrl == null)
            {
                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture,
                                                                  "Received a LogoutRequest from \"{0}\" but cannot reply because on logout endpoint is " +
                                                                  "configured on the idp. Set a SingleLogoutServiceUrl if the idp is configured manually, " +
                                                                  "or check that the idp metadata contains a SingleLogoutService endpoint.",
                                                                  idp.EntityId.Id));
            }

            var response = new Saml2LogoutResponse(Saml2StatusCode.Success)
            {
                DestinationUrl     = idp.SingleLogoutServiceResponseUrl,
                SigningCertificate = options.SPOptions.SigningServiceCertificate,
                SigningAlgorithm   = idp.OutboundSigningAlgorithm,
                InResponseTo       = request.Id,
                Issuer             = options.SPOptions.EntityId,
                RelayState         = unbindResult.RelayState
            };

            options.Notifications.LogoutResponseCreated(response, request, httpRequest.User, idp);

            options.SPOptions.Logger.WriteInformation("Got a logout request " + request.Id
                                                      + ", responding with logout response " + response.Id);

            var result = Saml2Binding.Get(idp.SingleLogoutServiceBinding).Bind(
                response, options.SPOptions.Logger, options.Notifications.LogoutResponseXmlCreated);

            result.TerminateLocalSession = true;
            return(result);
        }
예제 #4
0
        /// <summary>
        /// Run the command, initiating or handling the assertion consumer sequence.
        /// </summary>
        /// <param name="request">Request data.</param>
        /// <param name="options">Options</param>
        /// <returns>CommandResult</returns>
        public CommandResult Run(HttpRequestData request, IOptions options)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            var binding = options.Notifications.GetBinding(request);

            if (binding != null)
            {
                UnbindResult unbindResult = null;
                try
                {
                    unbindResult = binding.Unbind(request, options);
                    options.Notifications.MessageUnbound(unbindResult);

                    var samlResponse = new Saml2Response(unbindResult.Data, request.StoredRequestState?.MessageId, options);

                    var result = ProcessResponse(options, samlResponse, request.StoredRequestState);
                    if (unbindResult.RelayState != null)
                    {
                        result.ClearCookieName = StoredRequestState.CookieNameBase + unbindResult.RelayState;
                    }
                    options.Notifications.AcsCommandResultCreated(result, samlResponse);
                    return(result);
                }
                catch (FormatException ex)
                {
                    throw new BadFormatSamlResponseException(
                              "The SAML Response did not contain valid BASE64 encoded data.", ex);
                }
                catch (XmlException ex)
                {
                    var newEx = new BadFormatSamlResponseException(
                        "The SAML response contains incorrect XML", ex);

                    // Add the payload to the exception
                    if (unbindResult != null)
                    {
                        newEx.Data["Saml2Response"] = unbindResult.Data.OuterXml;
                    }
                    throw newEx;
                }
                catch (Exception ex)
                {
                    if (unbindResult != null)
                    {
                        // Add the payload to the existing exception
                        ex.Data["Saml2Response"] = unbindResult.Data.OuterXml;
                    }
                    throw;
                }
            }

            throw new NoSamlResponseFoundException();
        }