/// <summary>
        /// Transfers the client.
        /// </summary>
        /// <param name="idp">The identity provider.</param>
        /// <param name="context">The context.</param>
        private void TransferClient(IdentityProviderElement idp, HttpContext context)
        {
            var request = Saml20LogoutRequest.GetDefault();

            // Determine which endpoint to use from the configuration file or the endpoint metadata.
            var destination = DetermineEndpointConfiguration(BindingType.Redirect, idp.Endpoints.LogoutEndpoint, idp.Metadata.IDPSLOEndpoints);
            request.Destination = destination.Url;

            var nameIdFormat = StateService.Get<string>(IdpNameIdFormat);
            request.SubjectToLogOut.Format = nameIdFormat;

            // Handle POST binding
            if (destination.Binding == BindingType.Post)
            {
                var builder = new HttpPostBindingBuilder(destination);
                request.Destination = destination.Url;
                request.Reason = Saml20Constants.Reasons.User;
                request.SubjectToLogOut.Value = StateService.Get<string>(IdpNameId);
                request.SessionIndex = StateService.Get<string>(IdpSessionIdKey);

                var requestDocument = request.GetXml();
                XmlSignatureUtils.SignDocument(requestDocument, request.Id);
                builder.Request = requestDocument.OuterXml;

                Logger.DebugFormat(TraceMessages.LogoutRequestSent, idp.Id, "POST", builder.Request);

                builder.GetPage().ProcessRequest(context);
                context.Response.End();
                return;
            }

            // Handle Redirect binding
            if (destination.Binding == BindingType.Redirect)
            {
                request.Destination = destination.Url;
                request.Reason = Saml20Constants.Reasons.User;
                request.SubjectToLogOut.Value = StateService.Get<string>(IdpNameId);
                request.SessionIndex = StateService.Get<string>(IdpSessionIdKey);

                var builder = new HttpRedirectBindingBuilder
                                  {
                                      Request = request.GetXml().OuterXml,
                                      SigningKey = Saml2Config.GetConfig().ServiceProvider.SigningCertificate.GetCertificate().PrivateKey
                                  };

                var redirectUrl = destination.Url + "?" + builder.ToQuery();
                Logger.DebugFormat(TraceMessages.LogoutRequestSent, idp.Id, "REDIRECT", redirectUrl);

                context.Response.Redirect(redirectUrl, true);
                return;
            }

            // Handle Artifact binding
            if (destination.Binding == BindingType.Artifact)
            {
                request.Destination = destination.Url;
                request.Reason = Saml20Constants.Reasons.User;
                request.SubjectToLogOut.Value = StateService.Get<string>(IdpNameId);
                request.SessionIndex = StateService.Get<string>(IdpSessionIdKey);

                Logger.DebugFormat(TraceMessages.LogoutRequestSent, idp.Id, "ARTIFACT", request.GetXml().OuterXml);

                var builder = new HttpArtifactBindingBuilder(context);
                builder.RedirectFromLogout(destination, request, Guid.NewGuid().ToString("N"));
            }

            Logger.Error(ErrorMessages.EndpointBindingInvalid);
            throw new Saml20Exception(ErrorMessages.EndpointBindingInvalid);
        }
        /// <summary>
        /// Handles the SOAP message.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="inputStream">The input stream.</param>
        private void HandleSoap(HttpContext context, Stream inputStream)
        {
            var parser = new HttpArtifactBindingParser(inputStream);
            Logger.DebugFormat(TraceMessages.SOAPMessageParse, parser.SamlMessage.OuterXml);

            var builder = new HttpArtifactBindingBuilder(context);
            var config = Saml2Config.GetConfig();
            var idp = RetrieveIDPConfiguration(parser.Issuer);

            if (parser.IsArtifactResolve)
            {
                Logger.DebugFormat(TraceMessages.ArtifactResolveReceived, parser.SamlMessage);

                if (!parser.CheckSamlMessageSignature(idp.Metadata.Keys))
                {
                    Logger.ErrorFormat(ErrorMessages.ArtifactResolveSignatureInvalid);
                    throw new Saml20Exception(ErrorMessages.ArtifactResolveSignatureInvalid);
                }

                builder.RespondToArtifactResolve(parser.ArtifactResolve);
            }
            else if (parser.IsArtifactResponse)
            {
                Logger.DebugFormat(TraceMessages.ArtifactResponseReceived, parser.SamlMessage);

                if (!parser.CheckSamlMessageSignature(idp.Metadata.Keys))
                {
                    Logger.Error(ErrorMessages.ArtifactResponseSignatureInvalid);
                    throw new Saml20Exception(ErrorMessages.ArtifactResponseSignatureInvalid);
                }

                var status = parser.ArtifactResponse.Status;
                if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success)
                {
                    Logger.ErrorFormat(ErrorMessages.ArtifactResponseStatusCodeInvalid, status.StatusCode.Value);
                    throw new Saml20Exception(string.Format(ErrorMessages.ArtifactResponseStatusCodeInvalid, status.StatusCode.Value));
                }

                if (parser.ArtifactResponse.Any.LocalName == LogoutRequest.ElementName)
                {
                    Logger.DebugFormat(TraceMessages.LogoutRequestReceived, parser.ArtifactResponse.Any.OuterXml);

                    var req = Serialization.DeserializeFromXmlString<LogoutRequest>(parser.ArtifactResponse.Any.OuterXml);

                    // Send logoutresponse via artifact
                    var response = new Saml20LogoutResponse
                                       {
                                           Issuer = config.ServiceProvider.Id,
                                           StatusCode = Saml20Constants.StatusCodes.Success,
                                           InResponseTo = req.Id
                                       };

                    var endpoint = RetrieveIDPConfiguration(StateService.Get<string>(IdpLoginSessionKey));
                    var destination = DetermineEndpointConfiguration(BindingType.Redirect, endpoint.Endpoints.LogoutEndpoint, endpoint.Metadata.IDPSLOEndpoints);

                    builder.RedirectFromLogout(destination, response);
                }
                else if (parser.ArtifactResponse.Any.LocalName == LogoutResponse.ElementName)
                {
                    DoLogout(context);
                }
                else
                {
                    Logger.ErrorFormat(ErrorMessages.ArtifactResponseMissingResponse);
                    throw new Saml20Exception(ErrorMessages.ArtifactResponseMissingResponse);
                }
            }
            else if (parser.IsLogoutReqest)
            {
                Logger.DebugFormat(TraceMessages.LogoutRequestReceived, parser.SamlMessage.OuterXml);

                var req = parser.LogoutRequest;

                // Build the response object
                var response = new Saml20LogoutResponse
                                   {
                                       Issuer = config.ServiceProvider.Id,
                                       StatusCode = Saml20Constants.StatusCodes.Success,
                                       InResponseTo = req.Id
                                   };

                // response.Destination = destination.Url;
                var doc = response.GetXml();
                XmlSignatureUtils.SignDocument(doc, response.Id);
                if (doc.FirstChild is XmlDeclaration)
                {
                    doc.RemoveChild(doc.FirstChild);
                }

                builder.SendResponseMessage(doc.OuterXml);
            }
            else
            {
                Logger.ErrorFormat(ErrorMessages.SOAPMessageUnsupportedSamlMessage);
                throw new Saml20Exception(ErrorMessages.SOAPMessageUnsupportedSamlMessage);
            }
        }
        /// <summary>
        /// Handles the artifact.
        /// </summary>
        /// <param name="context">The context.</param>
        private void HandleArtifact(HttpContext context)
        {
            var builder = new HttpArtifactBindingBuilder(context);
            var inputStream = builder.ResolveArtifact();

            HandleSoap(context, inputStream);
        }
        /// <summary>
        /// Transfers the client.
        /// </summary>
        /// <param name="identityProvider">The identity provider.</param>
        /// <param name="request">The request.</param>
        /// <param name="context">The context.</param>
        private void TransferClient(IdentityProviderElement identityProvider, Saml20AuthnRequest request, HttpContext context)
        {
            // Set the last IDP we attempted to login at.
            StateService.Set(IdpTempSessionKey, identityProvider.Id);

            // Determine which endpoint to use from the configuration file or the endpoint metadata.
            var destination = DetermineEndpointConfiguration(BindingType.Redirect, identityProvider.Endpoints.SignOnEndpoint, identityProvider.Metadata.SSOEndpoints);
            request.Destination = destination.Url;

            if (identityProvider.ForceAuth)
            {
                request.ForceAuthn = true;
            }

            // Check isPassive status
            var isPassiveFlag = StateService.Get<bool?>(IdpIsPassive);

            if (isPassiveFlag != null && (bool)isPassiveFlag)
            {
                request.IsPassive = true;
                StateService.Set(IdpIsPassive, null);
            }

            if (identityProvider.IsPassive)
            {
                request.IsPassive = true;
            }

            // Check if request should forceAuthn
            var forceAuthnFlag = StateService.Get<bool?>(IdpForceAuthn);
            if (forceAuthnFlag != null && (bool)forceAuthnFlag)
            {
                request.ForceAuthn = true;
                StateService.Set(IdpForceAuthn, null);
            }

            // Check if protocol binding should be forced
            if (identityProvider.Endpoints.SignOnEndpoint != null)
            {
                if (!string.IsNullOrEmpty(identityProvider.Endpoints.SignOnEndpoint.ForceProtocolBinding))
                {
                    request.ProtocolBinding = identityProvider.Endpoints.SignOnEndpoint.ForceProtocolBinding;
                }
            }

            // Save request message id to session
            StateService.Set(ExpectedInResponseToSessionKey, request.Id);

            switch (destination.Binding)
            {
                case BindingType.Redirect:
                    Logger.DebugFormat(TraceMessages.AuthnRequestPrepared, identityProvider.Id, Saml20Constants.ProtocolBindings.HttpRedirect);

                    var redirectBuilder = new HttpRedirectBindingBuilder
                                      {
                                          SigningKey = _certificate.PrivateKey,
                                          Request = request.GetXml().OuterXml
                                      };

                    Logger.DebugFormat(TraceMessages.AuthnRequestSent, redirectBuilder.Request);

                    var redirectLocation = request.Destination + "?" + redirectBuilder.ToQuery();
                    context.Response.Redirect(redirectLocation, true);
                    break;
                case BindingType.Post:
                    Logger.DebugFormat(TraceMessages.AuthnRequestPrepared, identityProvider.Id, Saml20Constants.ProtocolBindings.HttpPost);

                    var postBuilder = new HttpPostBindingBuilder(destination);

                    // Honor the ForceProtocolBinding and only set this if it's not already set
                    if (string.IsNullOrEmpty(request.ProtocolBinding))
                    {
                        request.ProtocolBinding = Saml20Constants.ProtocolBindings.HttpPost;
                    }

                    var requestXml = request.GetXml();
                    XmlSignatureUtils.SignDocument(requestXml, request.Id);
                    postBuilder.Request = requestXml.OuterXml;

                    Logger.DebugFormat(TraceMessages.AuthnRequestSent, postBuilder.Request);

                    postBuilder.GetPage().ProcessRequest(context);
                    break;
                case BindingType.Artifact:
                    Logger.DebugFormat(TraceMessages.AuthnRequestPrepared, identityProvider.Id, Saml20Constants.ProtocolBindings.HttpArtifact);

                    var artifactBuilder = new HttpArtifactBindingBuilder(context);

                    // Honor the ForceProtocolBinding and only set this if it's not already set
                    if (string.IsNullOrEmpty(request.ProtocolBinding))
                    {
                        request.ProtocolBinding = Saml20Constants.ProtocolBindings.HttpArtifact;
                    }

                    Logger.DebugFormat(TraceMessages.AuthnRequestSent, request.GetXml().OuterXml);

                    artifactBuilder.RedirectFromLogin(destination, request);
                    break;
                default:
                    Logger.Error(ErrorMessages.EndpointBindingInvalid);
                    throw new Saml20Exception(ErrorMessages.EndpointBindingInvalid);
            }
        }
        /// <summary>
        /// Handles the SOAP.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="inputStream">The input stream.</param>
        private void HandleSoap(HttpContext context, Stream inputStream)
        {
            var parser = new HttpArtifactBindingParser(inputStream);
            Logger.DebugFormat(TraceMessages.SOAPMessageParse, parser.SamlMessage.OuterXml);

            var builder = new HttpArtifactBindingBuilder(context);

            if (parser.IsArtifactResolve)
            {
                Logger.Debug(TraceMessages.ArtifactResolveReceived);

                var idp = RetrieveIDPConfiguration(parser.Issuer);
                if (!parser.CheckSamlMessageSignature(idp.Metadata.Keys))
                {
                    Logger.Error(ErrorMessages.ArtifactResolveSignatureInvalid);
                    throw new Saml20Exception(ErrorMessages.ArtifactResolveSignatureInvalid);
                }

                builder.RespondToArtifactResolve(parser.ArtifactResolve);
            }
            else if (parser.IsArtifactResponse)
            {
                Logger.Debug(TraceMessages.ArtifactResolveReceived);

                var idp = RetrieveIDPConfiguration(parser.Issuer);
                if (!parser.CheckSamlMessageSignature(idp.Metadata.Keys))
                {
                    Logger.Error(ErrorMessages.ArtifactResponseSignatureInvalid);
                    throw new Saml20Exception(ErrorMessages.ArtifactResponseSignatureInvalid);
                }

                var status = parser.ArtifactResponse.Status;
                if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success)
                {
                    Logger.ErrorFormat(ErrorMessages.ArtifactResponseStatusCodeInvalid, status.StatusCode.Value);
                    throw new Saml20Exception(string.Format(ErrorMessages.ArtifactResponseStatusCodeInvalid, status.StatusCode.Value));
                }

                if (parser.ArtifactResponse.Any.LocalName == Response.ElementName)
                {
                    if (!idp.AllowUnsolicitedResponses)
                    {
                        CheckReplayAttack(context, parser.ArtifactResponse.Any);
                    }

                    var responseStatus = GetStatusElement(parser.ArtifactResponse.Any);
                    if (responseStatus.StatusCode.Value != Saml20Constants.StatusCodes.Success)
                    {
                        Logger.ErrorFormat(ErrorMessages.ArtifactResponseStatusCodeInvalid, responseStatus.StatusCode.Value);
                        throw new Saml20Exception(string.Format(ErrorMessages.ArtifactResponseStatusCodeInvalid, responseStatus.StatusCode.Value));
                    }

                    bool isEncrypted;
                    var assertion = GetAssertion(parser.ArtifactResponse.Any, out isEncrypted);
                    if (assertion == null)
                    {
                        Logger.Error(ErrorMessages.ArtifactResponseMissingAssertion);
                        throw new Saml20Exception(ErrorMessages.ArtifactResponseMissingAssertion);
                    }

                    if (isEncrypted)
                    {
                        HandleEncryptedAssertion(context, assertion);
                    }
                    else
                    {
                        HandleAssertion(context, assertion);
                    }
                }
                else
                {
                    Logger.ErrorFormat(ErrorMessages.ArtifactResponseMissingResponse);
                    throw new Saml20Exception(ErrorMessages.ArtifactResponseMissingResponse);
                }
            }
            else
            {
                Logger.ErrorFormat(ErrorMessages.SOAPMessageUnsupportedSamlMessage);
                throw new Saml20Exception(ErrorMessages.SOAPMessageUnsupportedSamlMessage);
            }
        }
Example #6
0
        /// <summary>
        /// Handles the SOAP.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="inputStream">The input stream.</param>
        public static void HandleSoap(HttpArtifactBindingBuilder builder, Stream inputStream, Saml2Configuration config, Action<Saml20Assertion> signonCallback, Func<string, object> getFromCache, Action<string, object, DateTime> setInCache, IDictionary<string, object> session)
        {
            var parser = new HttpArtifactBindingParser(inputStream);
            logger.DebugFormat(TraceMessages.SOAPMessageParse, parser.SamlMessage.OuterXml);

            if (parser.IsArtifactResolve) {
                logger.Debug(TraceMessages.ArtifactResolveReceived);

                var idp = IdpSelectionUtil.RetrieveIDPConfiguration(parser.Issuer, config);
                if (!parser.CheckSamlMessageSignature(idp.Metadata.Keys)) {
                    logger.Error(ErrorMessages.ArtifactResolveSignatureInvalid);
                    throw new Saml20Exception(ErrorMessages.ArtifactResolveSignatureInvalid);
                }

                builder.RespondToArtifactResolve(parser.ArtifactResolve, ((XmlDocument)getFromCache(parser.ArtifactResolve.Artifact)).DocumentElement);
            } else if (parser.IsArtifactResponse) {
                logger.Debug(TraceMessages.ArtifactResolveReceived);

                var idp = IdpSelectionUtil.RetrieveIDPConfiguration(parser.Issuer, config);
                if (!parser.CheckSamlMessageSignature(idp.Metadata.Keys)) {
                    logger.Error(ErrorMessages.ArtifactResponseSignatureInvalid);
                    throw new Saml20Exception(ErrorMessages.ArtifactResponseSignatureInvalid);
                }

                var status = parser.ArtifactResponse.Status;
                if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success) {
                    logger.ErrorFormat(ErrorMessages.ArtifactResponseStatusCodeInvalid, status.StatusCode.Value);
                    throw new Saml20Exception(string.Format(ErrorMessages.ArtifactResponseStatusCodeInvalid, status.StatusCode.Value));
                }

                if (parser.ArtifactResponse.Any.LocalName == Response.ElementName) {
                    Utility.CheckReplayAttack(parser.ArtifactResponse.Any, true, session);

                    var responseStatus = Utility.GetStatusElement(parser.ArtifactResponse.Any);
                    if (responseStatus.StatusCode.Value != Saml20Constants.StatusCodes.Success) {
                        logger.ErrorFormat(ErrorMessages.ArtifactResponseStatusCodeInvalid, responseStatus.StatusCode.Value);
                        throw new Saml20Exception(string.Format(ErrorMessages.ArtifactResponseStatusCodeInvalid, responseStatus.StatusCode.Value));
                    }

                    bool isEncrypted;
                    var assertion = Utility.GetAssertion(parser.ArtifactResponse.Any, out isEncrypted);
                    if (assertion == null) {
                        logger.Error(ErrorMessages.ArtifactResponseMissingAssertion);
                        throw new Saml20Exception(ErrorMessages.ArtifactResponseMissingAssertion);
                    }

                    var samlAssertion = isEncrypted
                        ? Utility.HandleEncryptedAssertion(assertion, config, getFromCache, setInCache)
                        : Utility.HandleAssertion(assertion, config, getFromCache, setInCache);
                    signonCallback(samlAssertion);
                } else {
                    logger.ErrorFormat(ErrorMessages.ArtifactResponseMissingResponse);
                    throw new Saml20Exception(ErrorMessages.ArtifactResponseMissingResponse);
                }
            } else {
                logger.ErrorFormat(ErrorMessages.SOAPMessageUnsupportedSamlMessage);
                throw new Saml20Exception(ErrorMessages.SOAPMessageUnsupportedSamlMessage);
            }
        }