예제 #1
0
        /// <summary>
        /// Resolves an artifact.
        /// </summary>
        /// <returns>A stream containing the artifact response from the IdP</returns>
        /// <param name="artifact">artifact from request ("SAMLart")</param>
        public Stream ResolveArtifact(string artifact, string relayState, Saml2Configuration config)
        {
            var idpEndPoint = DetermineIdp(artifact);

            if (idpEndPoint == null)
            {
                throw new InvalidOperationException(ErrorMessages.ArtifactResolveIdentityProviderUnknown);
            }

            var endpointIndex = ArtifactUtil.GetEndpointIndex(artifact);
            var endpointUrl   = idpEndPoint.Metadata.GetIDPARSEndpoint(endpointIndex);

            _logger.LogDebug(TraceMessages.ArtifactResolveForKnownIdentityProvider, artifact, idpEndPoint.Id, endpointUrl);

            var resolve = Saml20ArtifactResolve.GetDefault(config.ServiceProvider.Id);

            resolve.Artifact = artifact;

            var doc = resolve.GetXml();

            if (doc.FirstChild is XmlDeclaration)
            {
                doc.RemoveChild(doc.FirstChild);
            }

            XmlSignatureUtils.SignDocument(doc, resolve.Id, config);

            var artifactResolveString = doc.OuterXml;

            _logger.LogDebug(TraceMessages.ArtifactResolved, artifactResolveString);

            return(GetResponse(endpointUrl, artifactResolveString, idpEndPoint.ArtifactResolution, relayState));
        }
        /// <summary>
        /// Resolves an artifact.
        /// </summary>
        /// <returns>A stream containing the artifact response from the IdP</returns>
        public Stream ResolveArtifact()
        {
            var artifact    = Context.Request.Params["SAMLart"];
            var idpEndPoint = DetermineIdp(artifact);

            if (idpEndPoint == null)
            {
                throw new InvalidOperationException(ErrorMessages.ArtifactResolveIdentityProviderUnknown);
            }

            var endpointIndex = ArtifactUtil.GetEndpointIndex(artifact);
            var endpointUrl   = idpEndPoint.Metadata.GetIDPARSEndpoint(endpointIndex);

            Logger.DebugFormat(TraceMessages.ArtifactResolveForKnownIdentityProvider, artifact, idpEndPoint.Id, endpointUrl);
            var config  = ConfigurationFactory.Instance.Configuration;
            var resolve = Saml20ArtifactResolve.GetDefault(config.ServiceProvider.Id);

            resolve.Artifact = artifact;

            var doc = resolve.GetXml();

            if (doc.FirstChild is XmlDeclaration)
            {
                doc.RemoveChild(doc.FirstChild);
            }

            XmlSignatureUtils.SignDocument(doc, resolve.Id, config.ServiceProvider.SigningCertificate);

            var artifactResolveString = doc.OuterXml;

            Logger.DebugFormat(TraceMessages.ArtifactResolved, artifactResolveString);

            return(GetResponse(endpointUrl, artifactResolveString, idpEndPoint.ArtifactResolution));
        }
예제 #3
0
        /// <summary>
        ///     Resolves an artifact.
        /// </summary>
        /// <returns>A stream containing the artifact response from the IdP</returns>
        public Stream ResolveArtifact(string artifact, string artifactResolveEndpoint, string serviceProviderId,
                                      X509Certificate2 cert)
        {
            if (artifactResolveEndpoint == null)
            {
                throw new InvalidOperationException("Received artifact from unknown IDP.");
            }

            var resolve = new Saml2ArtifactResolve
            {
                Issuer   = serviceProviderId,
                Artifact = artifact
            };

            var doc = resolve.GetXml();

            if (doc.FirstChild is XmlDeclaration)
            {
                doc.RemoveChild(doc.FirstChild);
            }

            XmlSignatureUtils.SignDocument(doc, resolve.ID, cert);

            var artifactResolveString = doc.OuterXml;

            return(GetResponse(artifactResolveEndpoint, artifactResolveString));
        }
        private static void SignMessage(ref XDocument xDocument, X509Certificate2 clientCertificate)
        {
            // Add id's to elements that needs to be signed.
            var namespaceManager = new XmlNamespaceManager(new NameTable());

            namespaceManager.AddNamespace("a", WsaNamespace);
            namespaceManager.AddNamespace("s", S11Namespace);
            namespaceManager.AddNamespace("wsse", Wsse10Namespace);
            namespaceManager.AddNamespace("wsu", WsuNamespace);
            var actionElement              = xDocument.XPathSelectElement("/s:Envelope/s:Header/a:Action", namespaceManager);
            var msgElement                 = xDocument.XPathSelectElement("/s:Envelope/s:Header/a:MessageID", namespaceManager);
            var toElement                  = xDocument.XPathSelectElement("/s:Envelope/s:Header/a:To", namespaceManager);
            var timeStampElement           = xDocument.XPathSelectElement("/s:Envelope/s:Header/wsse:Security/wsu:Timestamp", namespaceManager);
            var binarySecurityTokenElement = xDocument.XPathSelectElement("/s:Envelope/s:Header/wsse:Security/wsse:BinarySecurityToken", namespaceManager);
            var bodyElement                = xDocument.XPathSelectElement("/s:Envelope/s:Body", namespaceManager);
            var idXName = XName.Get("Id", WsuNamespace);

            actionElement.Add(new XAttribute(idXName, ActionIdValue));
            msgElement.Add(new XAttribute(idXName, MessageIdIdValue));
            toElement.Add(new XAttribute(idXName, ToIdValue));
            timeStampElement.Add(new XAttribute(idXName, TimeStampIdValue));
            binarySecurityTokenElement.Add(new XAttribute(idXName, BinarySecurityTokenIdValue));
            bodyElement.Add(new XAttribute(idXName, BodyIdValue));

            var idOfElementsThatMustBeSigned = new List <string> {
                ActionIdValue, MessageIdIdValue, ToIdValue, TimeStampIdValue, BinarySecurityTokenIdValue, BodyIdValue
            };

            xDocument = XmlSignatureUtils.SignDocument(xDocument, idOfElementsThatMustBeSigned, clientCertificate);
        }
        /// <summary>
        ///     Resolves an artifact.
        /// </summary>
        /// <param name="providerName"></param>
        /// <returns>A stream containing the artifact response from the IdP</returns>
        public Stream ResolveArtifact(string providerName)
        {
            var artifactResolveEndpoint = _configurationProvider.GetIdentityProviderConfiguration(providerName).ArtifactResolveService;

            if (artifactResolveEndpoint == null)
            {
                throw new InvalidOperationException("Received artifact from unknown IDP.");
            }

            var serviceProviderId = _configurationProvider.ServiceProviderConfiguration.EntityId;
            var artifact          = GetArtifact();
            var resolve           = new Saml2ArtifactResolve
            {
                Issuer   = serviceProviderId,
                Artifact = artifact
            };

            var doc = resolve.GetXml();

            if (doc.FirstChild is XmlDeclaration)
            {
                doc.RemoveChild(doc.FirstChild);
            }

            var cert = _configurationProvider.ServiceProviderSigningCertificate();

            XmlSignatureUtils.SignDocument(doc, resolve.ID, cert);

            var artifactResolveString = doc.OuterXml;

            return(GetResponse(artifactResolveEndpoint, artifactResolveString));
        }
예제 #6
0
        /// <summary>
        /// Handles responses to an artifact resolve message.
        /// </summary>
        /// <param name="artifactResolve">The artifact resolve message.</param>
        public void RespondToArtifactResolve(ArtifactResolve artifactResolve)
        {
            XmlDocument samlDoc = (XmlDocument)_context.Cache.Get(artifactResolve.Artifact);

            Saml20ArtifactResponse response = Saml20ArtifactResponse.GetDefault();

            response.StatusCode   = Saml20Constants.StatusCodes.Success;
            response.InResponseTo = artifactResolve.ID;
            response.SamlElement  = samlDoc.DocumentElement;

            XmlDocument responseDoc = response.GetXml();

            if (responseDoc.FirstChild is XmlDeclaration)
            {
                responseDoc.RemoveChild(responseDoc.FirstChild);
            }

            XmlSignatureUtils.SignDocument(responseDoc, response.ID);

            if (Trace.ShouldTrace(TraceEventType.Information))
            {
                Trace.TraceData(TraceEventType.Information, string.Format(Tracing.RespondToArtifactResolve, artifactResolve.Artifact, responseDoc.OuterXml));
            }
            SendResponseMessage(responseDoc.OuterXml);
        }
예제 #7
0
 /// <summary>
 /// Creates an artifact for the LogoutRequest and redirects the user to the IdP.
 /// </summary>
 /// <param name="destination">The destination of the request.</param>
 /// <param name="request">The logout request.</param>
 /// <param name="relayState">The query string relay state value to add to the communication</param>
 public void RedirectFromLogout(IDPEndPointElement destination, Saml20LogoutRequest request, string relayState)
 {
     SAML20FederationConfig config = SAML20FederationConfig.GetConfig();
     Int16 index = (Int16)config.ServiceProvider.LogoutEndpoint.endPointIndex;
     XmlDocument doc = request.GetXml();
     XmlSignatureUtils.SignDocument(doc, request.Request.ID);
     ArtifactRedirect(destination, index, doc, relayState);
 }
        /// <summary>
        /// Creates an artifact and redirects the user to the IdP
        /// </summary>
        /// <param name="destination">The destination of the request.</param>
        /// <param name="request">The authentication request.</param>
        public void RedirectFromLogin(IdentityProviderEndpoint destination, Saml20AuthnRequest request)
        {
            var index = (short)config.ServiceProvider.Endpoints.DefaultSignOnEndpoint.Index;
            var doc   = request.GetXml();

            XmlSignatureUtils.SignDocument(doc, request.Request.Id, config.ServiceProvider.SigningCertificate);
            ArtifactRedirect(destination, index, doc, Context.Request.Params["relayState"]);
        }
        /// <summary>
        /// Creates an artifact for the LogoutRequest and redirects the user to the IdP.
        /// </summary>
        /// <param name="destination">The destination of the request.</param>
        /// <param name="request">The logout request.</param>
        /// <param name="relayState">The query string relay state value to add to the communication</param>
        public void RedirectFromLogout(IdentityProviderEndpoint destination, Saml20LogoutRequest request, string relayState)
        {
            var index = (short)config.ServiceProvider.Endpoints.DefaultLogoutEndpoint.Index;
            var doc   = request.GetXml();

            XmlSignatureUtils.SignDocument(doc, request.Request.Id, config.ServiceProvider.SigningCertificate);
            ArtifactRedirect(destination, index, doc, relayState);
        }
예제 #10
0
        /// <summary>
        /// Creates an artifact and redirects the user to the IdP
        /// </summary>
        /// <param name="destination">The destination of the request.</param>
        /// <param name="request">The authentication request.</param>
        /// <param name="relayState">Relay state from client. May be null</param>
        public void RedirectFromLogin(IdentityProviderEndpoint destination, Saml20AuthnRequest request, string relayState, Action <string, object> cacheInsert)
        {
            var index = (short)config.ServiceProvider.Endpoints.DefaultSignOnEndpoint.Index;
            var doc   = request.GetXml();

            XmlSignatureUtils.SignDocument(doc, request.Request.Id, config);
            ArtifactRedirect(destination, index, doc, relayState, cacheInsert);
        }
예제 #11
0
        /// <summary>
        /// Creates an artifact for the LogoutResponse and redirects the user to the IdP.
        /// </summary>
        /// <param name="destination">The destination of the response.</param>
        /// <param name="response">The logout response.</param>
        /// <param name="relayState">The query string relay state value to add to the communication</param>

        public void RedirectFromLogout(IdentityProviderEndpoint destination, Saml20LogoutResponse response, string relayState, Action <string, object> cacheInsert)
        {
            var index = (short)config.ServiceProvider.Endpoints.DefaultLogoutEndpoint.Index;
            var doc   = response.GetXml();

            XmlSignatureUtils.SignDocument(doc, response.Response.ID, config);

            ArtifactRedirect(destination, index, doc, relayState, cacheInsert);
        }
예제 #12
0
        /// <summary>
        /// Handles the SOAP message.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="inputStream">The input stream.</param>
        private async Task HandleSoap(IOwinContext context, Stream inputStream, NameValueCollection requestParams)
        {
            var config = options.Configuration;

            var parser = new HttpArtifactBindingParser(inputStream);

            Logger.DebugFormat(TraceMessages.SOAPMessageParse, parser.SamlMessage.OuterXml);

            var builder = GetBuilder(context);
            var idp     = IdpSelectionUtil.RetrieveIDPConfiguration(parser.Issuer, config);

            if (parser.IsLogoutReqest)
            {
                Logger.DebugFormat(TraceMessages.LogoutRequestReceived, parser.SamlMessage.OuterXml);

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

                var req = parser.LogoutRequest;

                var logoutRequestReceivedNotification = new LogoutRequestReceivedNotification <LogoutRequest, SamlAuthenticationOptions>(context, options)
                {
                    ProtocolMessage = req
                };

                await options.Notifications.LogoutRequestReceived(logoutRequestReceivedNotification);

                DoLogout(context, true);

                // 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, config.ServiceProvider.SigningCertificate);
                if (doc.FirstChild is XmlDeclaration)
                {
                    doc.RemoveChild(doc.FirstChild);
                }

                SendResponseMessage(doc.OuterXml, context);
            }
            else
            {
                Logger.ErrorFormat(ErrorMessages.SOAPMessageUnsupportedSamlMessage);
                throw new Saml20Exception(ErrorMessages.SOAPMessageUnsupportedSamlMessage);
            }
        }
예제 #13
0
        /// <summary>
        /// Creates an artifact for the LogoutResponse and redirects the user to the IdP.
        /// </summary>
        /// <param name="destination">The destination of the response.</param>
        /// <param name="response">The logout response.</param>
        public void RedirectFromLogout(IdentityProviderEndpoint destination, Saml20LogoutResponse response)
        {
            var config = Saml2Config.Current;
            var index  = (short)config.ServiceProvider.LogoutEndpoint.Index;
            var doc    = response.GetXml();

            XmlSignatureUtils.SignDocument(doc, response.Response.ID);

            ArtifactRedirect(destination, index, doc, Context.Request.Params["relayState"]);
        }
예제 #14
0
        /// <summary>
        /// Performs the attribute query against the specified IdP endpoint and adds the resulting attributes to <c>Saml20Identity.Current</c>.
        /// </summary>
        /// <param name="context">The http context.</param>
        /// <param name="endPoint">The IdP to perform the query against.</param>
        /// <param name="nameIdFormat">The name id format.</param>
        public void PerformQuery(HttpContext context, IdentityProviderElement endPoint, string nameIdFormat)
        {
            Logger.DebugFormat("{0}.{1} called", GetType(), "PerformQuery()");

            var builder = new HttpSoapBindingBuilder(context);

            var name = new NameId
            {
                Value  = Saml20Identity.Current.Name,
                Format = nameIdFormat
            };

            _attrQuery.Subject.Items = new object[] { name };
            _attrQuery.SamlAttribute = _attributes.ToArray();

            var query = new XmlDocument();

            query.LoadXml(Serialization.SerializeToXmlString(_attrQuery));

            XmlSignatureUtils.SignDocument(query, Id);
            if (query.FirstChild is XmlDeclaration)
            {
                query.RemoveChild(query.FirstChild);
            }

            Logger.DebugFormat(TraceMessages.AttrQuerySent, endPoint.Metadata.GetAttributeQueryEndpointLocation(), query.OuterXml);

            Stream s;

            try
            {
                s = builder.GetResponse(endPoint.Metadata.GetAttributeQueryEndpointLocation(), query.OuterXml, endPoint.AttributeQuery);
            }
            catch (Exception e)
            {
                Logger.Error(e.Message, e);
                throw;
            }

            var parser = new HttpSoapBindingParser(s);
            var status = parser.GetStatus();

            if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success)
            {
                Logger.ErrorFormat(ErrorMessages.AttrQueryStatusNotSuccessful, Serialization.SerializeToXmlString(status));
                throw new Saml20Exception(status.StatusMessage);
            }

            bool isEncrypted;
            var  xmlAssertion = Saml20SignonHandler.GetAssertion(parser.SamlMessage, out isEncrypted);

            if (isEncrypted)
            {
                var ass = new Saml20EncryptedAssertion((RSA)Saml2Config.GetConfig().ServiceProvider.SigningCertificat
예제 #15
0
        private Saml20AuthnRequest CreateAuthNRequest(Saml2Configuration config)
        {
            var authnRequest = Saml20AuthnRequest.GetDefault(config);
            var requestXml   = authnRequest.GetXml();

            if (config.ServiceProvider.AuthNRequestsSigned)
            {
                XmlSignatureUtils.SignDocument(requestXml, authnRequest.Id, config);
            }

            return(authnRequest);
        }
예제 #16
0
        public void SignatureTest()
        {
            // Arrange
            var rtsSoapMessageNotSigned = XDocument.Load(@"Resources\RST_Not_Signed.xml");
            var ids  = new[] { "action", "msgid", "to", "sec-ts", "sec-binsectoken", "body" };
            var cert = CertificateUtil.GetCertificate("0E6DBCC6EFAAFF72E3F3D824E536381B26DEECF5");

            // Act
            var rtsSoapMessageSigned = XmlSignatureUtils.SignDocument(rtsSoapMessageNotSigned, ids, cert);

            // Assert
            Assert.IsTrue(XmlSignatureUtils.VerifySignature(rtsSoapMessageSigned, cert));
        }
예제 #17
0
        private void CreateAssertionResponse(User user)
        {
            string entityId = request.Issuer.Value;
            Saml20MetadataDocument metadataDocument = IDPConfig.GetServiceProviderMetadata(entityId);
            IDPEndPointElement     endpoint         =
                metadataDocument.AssertionConsumerServiceEndpoints().Find(delegate(IDPEndPointElement e) { return(e.Binding == SAMLBinding.POST); });

            if (endpoint == null)
            {
                Context.Response.Write(string.Format("'{0}' does not have a SSO endpoint that supports the POST binding.", entityId));
                Context.Response.End();
                return;
            }

            UserSessionsHandler.AddLoggedInSession(entityId);

            Response response = new Response();

            response.Destination             = endpoint.Url;
            response.InResponseTo            = request.ID;
            response.Status                  = new Status();
            response.Status.StatusCode       = new StatusCode();
            response.Status.StatusCode.Value = Saml20Constants.StatusCodes.Success;

            Assertion assertion = CreateAssertion(user, entityId);

            response.Items = new object[] { assertion };

            // Serialize the response.
            XmlDocument assertionDoc = new XmlDocument();

            assertionDoc.XmlResolver        = null;
            assertionDoc.PreserveWhitespace = true;
            assertionDoc.LoadXml(Serialization.SerializeToXmlString(response));

            // Sign the assertion inside the response message.
            XmlSignatureUtils.SignDocument(assertionDoc, assertion.ID, IDPConfig.IDPCertificate);

            HttpPostBindingBuilder builder = new HttpPostBindingBuilder(endpoint);

            builder.Action   = SAMLAction.SAMLResponse;
            builder.Response = assertionDoc.OuterXml;

            builder.GetPage().ProcessRequest(Context);
            Context.Response.End();
        }
예제 #18
0
        /// <summary>
        /// Handles responses to an artifact resolve message.
        /// </summary>
        /// <param name="artifactResolve">The artifact resolve message.</param>
        public void RespondToArtifactResolve(ArtifactResolve artifactResolve, XmlElement samlDoc)
        {
            var response = Saml20ArtifactResponse.GetDefault(config.ServiceProvider.Id);

            response.StatusCode   = Saml20Constants.StatusCodes.Success;
            response.InResponseTo = artifactResolve.Id;
            response.SamlElement  = samlDoc; //samlDoc.DocumentElement;

            var responseDoc = response.GetXml();

            if (responseDoc.FirstChild is XmlDeclaration)
            {
                responseDoc.RemoveChild(responseDoc.FirstChild);
            }

            XmlSignatureUtils.SignDocument(responseDoc, response.Id, config);

            _logger.LogDebug(TraceMessages.ArtifactResolveResponseSent, artifactResolve.Artifact, responseDoc.OuterXml);

            sendResponseMessage(responseDoc.OuterXml);
        }
예제 #19
0
        /// <summary>
        /// Resolves an artifact.
        /// </summary>
        /// <returns>A stream containing the artifact response from the IdP</returns>
        public Stream ResolveArtifact()
        {
            Trace.TraceMethodCalled(GetType(), "ResolveArtifact()");

            string artifact = _context.Request.Params["SAMLart"];

            IDPEndPoint idpEndPoint = DetermineIdp(artifact);

            if (idpEndPoint == null)
            {
                throw new InvalidOperationException("Received artifact from unknown IDP.");
            }

            ushort endpointIndex = ArtifactUtil.GetEndpointIndex(artifact);

            string endpointUrl = idpEndPoint.metadata.GetARSEndpoint(endpointIndex);

            Saml20ArtifactResolve resolve = Saml20ArtifactResolve.GetDefault();

            resolve.Artifact = artifact;

            XmlDocument doc = resolve.GetXml();

            if (doc.FirstChild is XmlDeclaration)
            {
                doc.RemoveChild(doc.FirstChild);
            }

            XmlSignatureUtils.SignDocument(doc, resolve.ID);

            string artifactResolveString = doc.OuterXml;

            if (Trace.ShouldTrace(TraceEventType.Information))
            {
                Trace.TraceData(TraceEventType.Information, string.Format(Tracing.ResolveArtifact, artifact, idpEndPoint.Id, endpointIndex, endpointUrl, artifactResolveString));
            }

            return(GetResponse(endpointUrl, artifactResolveString, idpEndPoint.ArtifactResolution));
        }
        /// <summary>
        /// Handles responses to an artifact resolve message.
        /// </summary>
        /// <param name="artifactResolve">The artifact resolve message.</param>
        public void RespondToArtifactResolve(ArtifactResolve artifactResolve)
        {
            var samlDoc = (XmlDocument)Context.Cache.Get(artifactResolve.Artifact);

            var response = Saml20ArtifactResponse.GetDefault(config.ServiceProvider.Id);

            response.StatusCode   = Saml20Constants.StatusCodes.Success;
            response.InResponseTo = artifactResolve.Id;
            response.SamlElement  = samlDoc.DocumentElement;

            var responseDoc = response.GetXml();

            if (responseDoc.FirstChild is XmlDeclaration)
            {
                responseDoc.RemoveChild(responseDoc.FirstChild);
            }

            XmlSignatureUtils.SignDocument(responseDoc, response.Id, config.ServiceProvider.SigningCertificate);

            Logger.DebugFormat(TraceMessages.ArtifactResolveResponseSent, artifactResolve.Artifact, responseDoc.OuterXml);

            SendResponseMessage(responseDoc.OuterXml);
        }
예제 #21
0
        /// <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, Saml2Configuration config)
        {
            var parser = new HttpArtifactBindingParser(inputStream);

            Logger.DebugFormat(TraceMessages.SOAPMessageParse, parser.SamlMessage.OuterXml);

            var builder = GetBuilder(context);
            var idp     = IdpSelectionUtil.RetrieveIDPConfiguration(parser.Issuer, config);

            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, parser.SamlMessage);
            }
            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    = IdpSelectionUtil.RetrieveIDPConfiguration((string)context.Session[IdpLoginSessionKey], config);
                    var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Redirect, endpoint.Endpoints.DefaultLogoutEndpoint, endpoint.Metadata.IDPSLOEndpoints);

                    builder.RedirectFromLogout(destination, response, context.Request.Params["relayState"], (s, o) => context.Cache.Insert(s, o, null, DateTime.Now.AddMinutes(1), Cache.NoSlidingExpiration));
                }
                else if (parser.ArtifactResponse.Any.LocalName == LogoutResponse.ElementName)
                {
                    DoLogout(context, false, config);
                }
                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, config);
                if (doc.FirstChild is XmlDeclaration)
                {
                    doc.RemoveChild(doc.FirstChild);
                }

                SendResponseMessage(doc.OuterXml, context);
            }
            else
            {
                Logger.ErrorFormat(ErrorMessages.SOAPMessageUnsupportedSamlMessage);
                throw new Saml20Exception(ErrorMessages.SOAPMessageUnsupportedSamlMessage);
            }
        }
예제 #22
0
        /// <summary>
        /// Handles the request.
        /// </summary>
        /// <param name="context">The context.</param>
        private void HandleRequest(HttpContext context)
        {
            Logger.DebugFormat(TraceMessages.LogoutRequestReceived);

            // Fetch the endpoint configuration
            var idp         = IdpSelectionUtil.RetrieveIDPConfiguration((string)context.Session[IdpLoginSessionKey], ConfigurationFactory.Instance.Configuration);
            var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Redirect, idp.Endpoints.DefaultLogoutEndpoint, idp.Metadata.IDPSLOEndpoints);

            // Fetch config object
            var config = ConfigurationFactory.Instance.Configuration;

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

            string message;

            if (context.Request.RequestType == "GET")
            {
                // HTTP Redirect binding
                var parser = new HttpRedirectBindingParser(context.Request.Url);
                Logger.DebugFormat(TraceMessages.LogoutRequestRedirectBindingParse, parser.Message, parser.SignatureAlgorithm, parser.Signature);

                var endpoint = config.IdentityProviders.FirstOrDefault(x => x.Id == idp.Id);
                if (endpoint == null || endpoint.Metadata == null)
                {
                    Logger.ErrorFormat(ErrorMessages.UnknownIdentityProvider, idp.Id);
                    throw new Saml20Exception(string.Format(ErrorMessages.UnknownIdentityProvider, idp.Id));
                }

                var metadata = endpoint.Metadata;
                if (!parser.VerifySignature(metadata.GetKeys(KeyTypes.Signing)))
                {
                    Logger.Error(ErrorMessages.RequestSignatureInvalid);
                    throw new Saml20Exception(ErrorMessages.RequestSignatureInvalid);
                }

                message = parser.Message;
            }
            else if (context.Request.RequestType == "POST")
            {
                // HTTP Post binding
                var parser = new HttpPostBindingParser(context.Request.Params);
                Logger.DebugFormat(TraceMessages.LogoutRequestPostBindingParse, parser.Message);

                if (!parser.IsSigned)
                {
                    Logger.Error(ErrorMessages.RequestSignatureMissing);
                    throw new Saml20Exception(ErrorMessages.RequestSignatureMissing);
                }

                var endpoint = config.IdentityProviders.FirstOrDefault(x => x.Id == idp.Id);
                if (endpoint == null || endpoint.Metadata == null)
                {
                    Logger.ErrorFormat(ErrorMessages.UnknownIdentityProvider, idp.Id);
                    throw new Saml20Exception(string.Format(ErrorMessages.UnknownIdentityProvider, idp.Id));
                }

                var metadata = endpoint.Metadata;

                // Check signature
                if (!parser.CheckSignature(metadata.GetKeys(KeyTypes.Signing)))
                {
                    Logger.Error(ErrorMessages.RequestSignatureInvalid);
                    throw new Saml20Exception(ErrorMessages.RequestSignatureInvalid);
                }

                message = parser.Message;
            }
            else
            {
                // Error: We don't support HEAD, PUT, CONNECT, TRACE, DELETE and OPTIONS
                Logger.ErrorFormat(ErrorMessages.UnsupportedRequestType, context.Request.RequestType);
                throw new Saml20Exception(string.Format(ErrorMessages.UnsupportedRequestType, context.Request.RequestType));
            }

            Logger.DebugFormat(TraceMessages.LogoutRequestParsed, message);

            // Log the user out locally
            DoLogout(context, true);

            var req = Serialization.DeserializeFromXmlString <LogoutRequest>(message);

            response.InResponseTo = req.Id;

            // Respond using redirect binding
            if (destination.Binding == BindingType.Redirect)
            {
                var builder = new HttpRedirectBindingBuilder
                {
                    RelayState = context.Request.Params["RelayState"],
                    Response   = response.GetXml().OuterXml,
                    SigningKey = config.ServiceProvider.SigningCertificate.PrivateKey
                };

                Logger.DebugFormat(TraceMessages.LogoutResponseSent, builder.Response);

                context.Response.Redirect(destination.Url + "?" + builder.ToQuery(), true);
                return;
            }

            // Respond using post binding
            if (destination.Binding == BindingType.Post)
            {
                var builder = new HttpPostBindingBuilder(destination)
                {
                    Action = SamlActionType.SAMLResponse
                };

                var responseDocument = response.GetXml();

                Logger.DebugFormat(TraceMessages.LogoutResponseSent, responseDocument.OuterXml);

                XmlSignatureUtils.SignDocument(responseDocument, response.Id, config);
                builder.Response   = responseDocument.OuterXml;
                builder.RelayState = context.Request.Params["RelayState"];
                context.Response.Write(builder.GetPage());
            }
        }
예제 #23
0
    private void CreateSAMLResponse()
    {
        FormsIdentity id = null;

        if (HttpContext.Current.User != null)
        {
            if (HttpContext.Current.User.Identity.IsAuthenticated)
            {
                if (HttpContext.Current.User.Identity is FormsIdentity)
                {
                    id = (FormsIdentity)HttpContext.Current.User.Identity;
                }
            }
        }

        DateTime notBefore    = (id != null ? id.Ticket.IssueDate.ToUniversalTime() : DateTime.UtcNow);
        DateTime notOnOrAfter = (id != null ? id.Ticket.Expiration.ToUniversalTime() : DateTime.UtcNow.AddMinutes(30));

        IDProvider config = IDProvider.GetConfig();

        SAMLResponse.Status                  = new StatusType();
        SAMLResponse.Status.StatusCode       = new StatusCodeType();
        SAMLResponse.Status.StatusCode.Value = SAMLUtility.StatusCodes.Success;

        AssertionType assert = new AssertionType();

        assert.ID           = SAMLUtility.GenerateID();
        assert.IssueInstant = DateTime.UtcNow.AddMinutes(10);

        assert.Issuer       = new NameIDType();
        assert.Issuer.Value = config.id;

        SubjectConfirmationType subjectConfirmation = new SubjectConfirmationType();

        subjectConfirmation.Method = "urn:oasis:names:tc:SAML:2.0:cm:bearer";
        subjectConfirmation.SubjectConfirmationData              = new SubjectConfirmationDataType();
        subjectConfirmation.SubjectConfirmationData.Recipient    = SAMLRequest.Issuer;
        subjectConfirmation.SubjectConfirmationData.InResponseTo = SAMLRequest.Request.ID;
        subjectConfirmation.SubjectConfirmationData.NotOnOrAfter = notOnOrAfter;

        NameIDType nameID = new NameIDType();

        nameID.Format = SAMLUtility.NameIdentifierFormats.Transient;
        nameID.Value  = (id != null ? id.Name : UtilBO.FormatNameFormsAuthentication(this.__SessionWEB.__UsuarioWEB.Usuario));

        assert.Subject       = new SubjectType();
        assert.Subject.Items = new object[] { subjectConfirmation, nameID };

        assert.Conditions                       = new ConditionsType();
        assert.Conditions.NotBefore             = notBefore;
        assert.Conditions.NotOnOrAfter          = notOnOrAfter;
        assert.Conditions.NotBeforeSpecified    = true;
        assert.Conditions.NotOnOrAfterSpecified = true;

        AudienceRestrictionType audienceRestriction = new AudienceRestrictionType();

        audienceRestriction.Audience = new string[] { SAMLRequest.Issuer };
        assert.Conditions.Items      = new ConditionAbstractType[] { audienceRestriction };

        AuthnStatementType authnStatement = new AuthnStatementType();

        authnStatement.AuthnInstant = DateTime.UtcNow;
        authnStatement.SessionIndex = SAMLUtility.GenerateID();

        authnStatement.AuthnContext       = new AuthnContextType();
        authnStatement.AuthnContext.Items =
            new object[] { "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport" };

        authnStatement.AuthnContext.ItemsElementName =
            new ItemsChoiceType5[] { ItemsChoiceType5.AuthnContextClassRef };

        StatementAbstractType[] statementAbstract = new StatementAbstractType[] { authnStatement };
        assert.Items       = statementAbstract;
        SAMLResponse.Items = new object[] { assert };

        string xmlResponse = SAMLUtility.SerializeToXmlString(SAMLResponse);

        XmlDocument doc = new XmlDocument();

        doc.LoadXml(xmlResponse);
        XmlSignatureUtils.SignDocument(doc, assert.ID);
        SAMLResponse = SAMLUtility.DeserializeFromXmlString <ResponseType>(doc.InnerXml);

        HttpPostBinding binding = new HttpPostBinding(SAMLResponse, HttpUtility.UrlDecode(Request[HttpBindingConstants.RelayState]));

        binding.SendResponse(this.Context, HttpUtility.UrlDecode(SAMLRequest.AssertionConsumerServiceURL), SAMLTypeSSO.signon);
    }
예제 #24
0
        /// <summary>
        /// Transfers the client.
        /// </summary>
        /// <param name="idp">The identity provider.</param>
        /// <param name="context">The context.</param>
        private void TransferClient(IdentityProvider idp, HttpContext context, Saml2Configuration config)
        {
            var request = Saml20LogoutRequest.GetDefault(config);

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

            request.Destination = destination.Url;

            var nameIdFormat = (string)context.Session[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 = (string)context.Session[IdpNameId];
                request.SessionIndex          = (string)context.Session[IdpSessionIdKey];

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

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

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

            // Handle Redirect binding
            if (destination.Binding == BindingType.Redirect)
            {
                request.Destination           = destination.Url;
                request.Reason                = Saml20Constants.Reasons.User;
                request.SubjectToLogOut.Value = (string)context.Session[IdpNameId];
                request.SessionIndex          = (string)context.Session[IdpSessionIdKey];

                var builder = new HttpRedirectBindingBuilder
                {
                    Request    = request.GetXml().OuterXml,
                    SigningKey = config.ServiceProvider.SigningCertificate.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 = (string)context.Session[IdpNameId];
                request.SessionIndex          = (string)context.Session[IdpSessionIdKey];

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

                var builder = GetBuilder(context);
                builder.RedirectFromLogout(destination, request, Guid.NewGuid().ToString("N"), (s, o) => context.Cache.Insert(s, o, null, DateTime.Now.AddMinutes(1), Cache.NoSlidingExpiration));
            }

            Logger.Error(ErrorMessages.EndpointBindingInvalid);
            throw new Saml20Exception(ErrorMessages.EndpointBindingInvalid);
        }
예제 #25
0
        private void HandleRequest(HttpContext context)
        {
            Trace.TraceMethodCalled(GetType(), "HandleRequest()");

            //Fetch config object
            SAML20FederationConfig config = SAML20FederationConfig.GetConfig();

            LogoutRequest logoutRequest = null;
            IDPEndPoint endpoint = null;
            string message = string.Empty;

            //Build the response object
            var response = new Saml20LogoutResponse();
            response.Issuer = config.ServiceProvider.ID;
            response.StatusCode = Saml20Constants.StatusCodes.Success; // Default success. Is overwritten if something fails.
            
            if(context.Request.RequestType == "GET") // HTTP Redirect binding
            {
                HttpRedirectBindingParser parser = new HttpRedirectBindingParser(context.Request.Url);
                AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST,
                                      string.Format("Binding: redirect, Signature algorithm: {0}  Signature:  {1}, Message: {2}", parser.SignatureAlgorithm, parser.Signature, parser.Message));

                if (!parser.IsSigned)
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Signature not present, msg: " + parser.Message);
                    response.StatusCode = Saml20Constants.StatusCodes.RequestDenied;
                }

                logoutRequest = parser.LogoutRequest;
                endpoint = config.FindEndPoint(logoutRequest.Issuer.Value);

                if (endpoint.metadata == null)
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Cannot find metadata for IdP: " + logoutRequest.Issuer.Value);
                    // Not able to return a response as we do not know the IdP.
                    HandleError(context, "Cannot find metadata for IdP " + logoutRequest.Issuer.Value);
                    return;
                }

                Saml20MetadataDocument metadata = endpoint.metadata;

                if (!parser.VerifySignature(metadata.GetKeys(KeyTypes.signing)))
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Request has been denied. Invalid signature redirect-binding, msg: " + parser.Message);
                    response.StatusCode = Saml20Constants.StatusCodes.RequestDenied;
                }

                message = parser.Message;
            }
            else if (context.Request.RequestType == "POST") // HTTP Post binding
            {
                HttpPostBindingParser parser = new HttpPostBindingParser(context);
                AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST,
                                      "Binding: POST, Message: " + parser.Message);

                if (!parser.IsSigned())
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Signature not present, msg: " + parser.Message);
                    response.StatusCode = Saml20Constants.StatusCodes.RequestDenied;
                }

                logoutRequest = parser.LogoutRequest;
                endpoint = config.FindEndPoint(logoutRequest.Issuer.Value);
                if (endpoint.metadata == null)
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Cannot find metadata for IdP");
                    // Not able to return a response as we do not know the IdP.
                    HandleError(context, "Cannot find metadata for IdP " + logoutRequest.Issuer.Value);
                    return;
                }

                Saml20MetadataDocument metadata = endpoint.metadata;

                // handle a logout-request
                if (!parser.CheckSignature(metadata.GetKeys(KeyTypes.signing)))
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Request has been denied. Invalid signature post-binding, msg: " + parser.Message);
                    response.StatusCode = Saml20Constants.StatusCodes.RequestDenied;
                }

                message = parser.Message;
            }else
            {
                //Error: We don't support HEAD, PUT, CONNECT, TRACE, DELETE and OPTIONS
                // Not able to return a response as we do not understand the request.
                HandleError(context, Resources.UnsupportedRequestTypeFormat(context.Request.RequestType));
            }

            AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, message);
            
            // Check that idp in session and request matches.
            string idpRequest = logoutRequest.Issuer.Value;
            if (!context.Session.IsNewSession)
            {
                object idpSession = context.Session[IDPLoginSessionKey];
            
                if (idpSession != null && idpSession.ToString() != idpRequest)
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, Resources.IdPMismatchBetweenRequestAndSessionFormat(idpSession, idpRequest), message);
                    response.StatusCode = Saml20Constants.StatusCodes.RequestDenied;
                }
            }
            else
            {
                // All other status codes than Success results in the IdP throwing an error page. Therefore we return default Success even if we do not have a session.
                AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Session does not exist. Continues the redirect logout procedure with status code success." + idpRequest, message);
            }

            //  Only logout if request is valid and we are working on an existing Session.
            if (Saml20Constants.StatusCodes.Success == response.StatusCode && !context.Session.IsNewSession)
            {
                // Execute all actions that the service provider has configured
                DoLogout(context, true);
            }

            // Update the response object with informations that first is available when request has been parsed.
            IDPEndPointElement destination = DetermineEndpointConfiguration(SAMLBinding.REDIRECT, endpoint.SLOEndpoint, endpoint.metadata.SLOEndpoints());
            response.Destination = destination.Url;
            response.InResponseTo = logoutRequest.ID;

            //Respond using redirect binding
            if(destination.Binding == SAMLBinding.REDIRECT)
            {
                HttpRedirectBindingBuilder builder = new HttpRedirectBindingBuilder();
                builder.RelayState = context.Request.Params["RelayState"];
                builder.Response = response.GetXml().OuterXml;
                builder.signingKey = FederationConfig.GetConfig().SigningCertificate.GetCertificate().PrivateKey;
                string s = destination.Url + "?" + builder.ToQuery();
                context.Response.Redirect(s, true);
                return;
            }

            //Respond using post binding
            if (destination.Binding == SAMLBinding.POST)
            {
                HttpPostBindingBuilder builder = new HttpPostBindingBuilder(destination);
                builder.Action = SAMLAction.SAMLResponse;                                
                XmlDocument responseDocument = response.GetXml();
                XmlSignatureUtils.SignDocument(responseDocument, response.ID);
                builder.Response = responseDocument.OuterXml;
                builder.RelayState = context.Request.Params["RelayState"];
                builder.GetPage().ProcessRequest(context);
                return;
            }
        }
예제 #26
0
        private void TransferClient(IDPEndPoint endpoint, HttpContext context)
        {
            Trace.TraceMethodCalled(GetType(), "TransferClient()");
            
            Saml20LogoutRequest request = Saml20LogoutRequest.GetDefault();
            
            AuditLogging.AssertionId = request.ID;
            AuditLogging.IdpId = endpoint.Id;
            
            // Determine which endpoint to use from the configuration file or the endpoint metadata.
            IDPEndPointElement destination =
                DetermineEndpointConfiguration(SAMLBinding.REDIRECT, endpoint.SLOEndpoint, endpoint.metadata.SLOEndpoints());
            
            request.Destination = destination.Url;

            string nameIdFormat = context.Session[IDPNameIdFormat].ToString();
            request.SubjectToLogOut.Format = nameIdFormat;
            
            if (destination.Binding == SAMLBinding.POST)
            {
                HttpPostBindingBuilder builder = new HttpPostBindingBuilder(destination);
                request.Destination = destination.Url;
                request.Reason = Saml20Constants.Reasons.User;
                request.SubjectToLogOut.Value = context.Session[IDPNameId].ToString();
                 request.SessionIndex = context.Session[IDPSessionIdKey].ToString();
                XmlDocument requestDocument = request.GetXml();
                XmlSignatureUtils.SignDocument(requestDocument, request.ID);
                builder.Request = requestDocument.OuterXml;

                if(Trace.ShouldTrace(TraceEventType.Information))
                    Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendLogoutRequest, "POST", endpoint.Id, requestDocument.OuterXml));

                AuditLogging.logEntry(Direction.OUT, Operation.LOGOUTREQUEST, "Binding: POST");
                builder.GetPage().ProcessRequest(context);
                context.Response.End();
                return;
            }

            if(destination.Binding == SAMLBinding.REDIRECT)
            {
                HttpRedirectBindingBuilder builder = new HttpRedirectBindingBuilder();
                builder.signingKey = FederationConfig.GetConfig().SigningCertificate.GetCertificate().PrivateKey;
                request.Destination = destination.Url;
                request.Reason = Saml20Constants.Reasons.User;
                request.SubjectToLogOut.Value = context.Session[IDPNameId].ToString();
                request.SessionIndex = context.Session[IDPSessionIdKey].ToString();
                builder.Request = request.GetXml().OuterXml;
                
                string redirectUrl = destination.Url + "?" + builder.ToQuery();

                if (Trace.ShouldTrace(TraceEventType.Information))
                    Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendLogoutRequest, "REDIRECT", endpoint.Id, redirectUrl));

                AuditLogging.logEntry(Direction.OUT, Operation.LOGOUTREQUEST, "Binding: Redirect");
                context.Response.Redirect(redirectUrl, true);
                return;
            }

            if(destination.Binding == SAMLBinding.ARTIFACT)
            {
                if (Trace.ShouldTrace(TraceEventType.Information))
                    Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendLogoutRequest, "ARTIFACT", endpoint.Id, string.Empty));

                request.Destination = destination.Url;
                request.Reason = Saml20Constants.Reasons.User;
                request.SubjectToLogOut.Value = context.Session[IDPNameId].ToString();
                request.SessionIndex = context.Session[IDPSessionIdKey].ToString();

                HttpArtifactBindingBuilder builder = new HttpArtifactBindingBuilder(context);
                AuditLogging.logEntry(Direction.OUT, Operation.LOGOUTREQUEST, "Method: Artifact");
                builder.RedirectFromLogout(destination, request, Guid.NewGuid().ToString("N"));
            }

            HandleError(context, Resources.BindingError);
        }
예제 #27
0
        private void HandleSOAP(HttpContext context, Stream inputStream)
        {
            Trace.TraceMethodCalled(GetType(), "HandleSOAP");

            HttpArtifactBindingParser parser = new HttpArtifactBindingParser(inputStream);
            HttpArtifactBindingBuilder builder = new HttpArtifactBindingBuilder(context);
            SAML20FederationConfig config = SAML20FederationConfig.GetConfig();

            IDPEndPoint idp = RetrieveIDPConfiguration(parser.Issuer);
            AuditLogging.IdpId = idp.Id;

            
            if (parser.IsArtifactResolve())
            {
                Trace.TraceData(TraceEventType.Information, Tracing.ArtifactResolveIn);

                if (!parser.CheckSamlMessageSignature(idp.metadata.Keys))
                {
                    HandleError(context, "Invalid Saml message signature");
                    AuditLogging.logEntry(Direction.UNDEFINED, Operation.ARTIFACTRESOLVE, "Signature could not be verified", parser.SamlMessage);
                }
                AuditLogging.AssertionId = parser.ArtifactResolve.ID;
                AuditLogging.logEntry(Direction.IN, Operation.ARTIFACTRESOLVE, "", parser.SamlMessage);
                builder.RespondToArtifactResolve(parser.ArtifactResolve);
            }
            else if (parser.IsArtifactResponse())
            {
                Trace.TraceData(TraceEventType.Information, Tracing.ArtifactResponseIn);

                Status status = parser.ArtifactResponse.Status;
                if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success)
                {
                    AuditLogging.logEntry(Direction.UNDEFINED, Operation.ARTIFACTRESOLVE, string.Format("Unexpected status code for artifact response: {0}, expected 'Success', msg: {1}", status.StatusCode.Value, parser.SamlMessage));
                    HandleError(context, status);
                    return;
                }

                if (parser.ArtifactResponse.Any.LocalName == LogoutRequest.ELEMENT_NAME)
                {
                    if(Trace.ShouldTrace(TraceEventType.Information))
                        Trace.TraceData(TraceEventType.Information, string.Format(Tracing.LogoutRequest, parser.ArtifactResponse.Any.OuterXml));

                    //Send logoutresponse via artifact
                    Saml20LogoutResponse response = new Saml20LogoutResponse();
                    response.Issuer = config.ServiceProvider.ID;
                    LogoutRequest req = Serialization.DeserializeFromXmlString<LogoutRequest>(parser.ArtifactResponse.Any.OuterXml);
                    response.StatusCode = Saml20Constants.StatusCodes.Success;
                    response.InResponseTo = req.ID;
                    IDPEndPoint endpoint = RetrieveIDPConfiguration(context.Session[IDPLoginSessionKey].ToString());
                    IDPEndPointElement destination =
                        DetermineEndpointConfiguration(SAMLBinding.REDIRECT, endpoint.SLOEndpoint, endpoint.metadata.SLOEndpoints());

                    builder.RedirectFromLogout(destination, response);
                }else if(parser.ArtifactResponse.Any.LocalName == LogoutResponse.ELEMENT_NAME)
                {
                    DoLogout(context);
                }
                else
                {
                    AuditLogging.logEntry(Direction.UNDEFINED, Operation.ARTIFACTRESOLVE, string.Format("Unsupported payload message in ArtifactResponse: {0}, msg: {1}", parser.ArtifactResponse.Any.LocalName, parser.SamlMessage));
                    HandleError(context,
                                string.Format("Unsupported payload message in ArtifactResponse: {0}",
                                              parser.ArtifactResponse.Any.LocalName));
                }
            }
            else if(parser.IsLogoutReqest())
            {
                if (Trace.ShouldTrace(TraceEventType.Information))
                    Trace.TraceData(TraceEventType.Information, string.Format(Tracing.LogoutRequest, parser.SamlMessage.OuterXml));

                LogoutRequest req = parser.LogoutRequest;
                
                //Build the response object
                Saml20LogoutResponse response = new Saml20LogoutResponse();
                response.Issuer = config.ServiceProvider.ID;
                //response.Destination = destination.Url;
                response.StatusCode = Saml20Constants.StatusCodes.Success;
                response.InResponseTo = req.ID;
                XmlDocument doc = response.GetXml();
                XmlSignatureUtils.SignDocument(doc, response.ID);
                if (doc.FirstChild is XmlDeclaration)
                    doc.RemoveChild(doc.FirstChild);
                
                builder.SendResponseMessage(doc.OuterXml);
                
            }
            else
            {
                Status s = parser.GetStatus();
                if (s != null)
                {
                    HandleError(context, s);
                }
                else
                {
                    AuditLogging.logEntry(Direction.UNDEFINED, Operation.ARTIFACTRESOLVE, string.Format("Unsupported SamlMessage element: {0}, msg: {1}", parser.SamlMessageName, parser.SamlMessage));
                    HandleError(context, string.Format("Unsupported SamlMessage element: {0}", parser.SamlMessageName));
                }
            }
        }
예제 #28
0
        /// <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(IdentityProvider 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.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.SignOnEndpoint != null)
            {
                if (!string.IsNullOrEmpty(identityProvider.SignOnEndpoint.ForceProtocolBinding))
                {
                    request.ProtocolBinding = identityProvider.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 + (request.Destination.Contains("?") ? "&" : "?") + 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);
            }
        }
예제 #29
0
        private void SendAuthNRequest(Saml2Configuration config)
        {
            _logger.LogDebug("Begin Transfer User to IDP");

            if (!config.IdentityProviders.Any())
            {
                _logger.LogError("No IdentityProviders configured");
            }

            // order signon endpoints by index and then check for default.



            var idp = (GetFirstIdp(config)?.Metadata.SSOEndpoints.FirstOrDefault(x => x.Binding == BindingType.Post && x.Type == EndpointType.SignOn)
                       ?? GetFirstIdp(config)?.Metadata.SSOEndpoints.FirstOrDefault(x => x.Binding == BindingType.Redirect && x.Type == EndpointType.SignOn));

            if (idp == null)
            {
                _logger.LogError("IdentityProvider configured does not have POST or Redirect binding", config.IdentityProviders.FirstOrDefault());
            }

            _logger.LogDebug($"IdentityProvider found: {idp.Binding.ToString()}");
            var authnRequest = CreateAuthNRequest(config);

            if (idp.Binding == BindingType.Post)
            {
                var post = new SAMLSilly.Bindings.HttpPostBindingBuilder(idp);

                if (string.IsNullOrEmpty(authnRequest.ProtocolBinding))
                {
                    authnRequest.ProtocolBinding = Saml20Constants.ProtocolBindings.HttpPost;
                }

                var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Post, idp, config.IdentityProviders[0].Metadata.SSOEndpoints);
                authnRequest.Destination = destination.Url;

                var requestXml = authnRequest.GetXml();
                if (config.ServiceProvider.AuthNRequestsSigned)
                {
                    _logger.LogDebug("Sign AuthNRequest");
                    XmlSignatureUtils.SignDocument(requestXml, authnRequest.Id, config);
                }
                post.Request = requestXml.OuterXml;

                _httpContextAccessor.HttpContext.Response.WriteAsync(post.GetPage());
                return;
            }
            else
            {
                var redirectBuilder = new SAMLSilly.AspNetCore.BindingBuilders.HttpRedirectBindingBuilder(config);

                // if (string.IsNullOrEmpty(authnRequest.ProtocolBinding))
                // {
                authnRequest.ProtocolBinding = Saml20Constants.ProtocolBindings.HttpPost;
                // }

                var destination = IdpSelectionUtil.DetermineEndpointConfiguration(BindingType.Redirect, idp, config.IdentityProviders[0].Metadata.SSOEndpoints);
                authnRequest.Destination = destination.Url;

                redirectBuilder.Request    = authnRequest.GetXml().OuterXml;
                redirectBuilder.SigningKey = config.ServiceProvider.SigningCertificate.PrivateKey;

                var query = redirectBuilder.ToQuery();
                var url   = $"{idp.Url}?{query}";

                _httpContextAccessor.HttpContext.Response.Redirect(url, false);
                return;
            }


            throw new NotImplementedException();
        }
        /// <summary>
        /// Performs the attribute query against the specified IdP endpoint and adds the resulting attributes to Saml20Identity.Current.
        /// </summary>
        /// <param name="context">The http context.</param>
        /// <param name="endPoint">The IdP to perform the query against.</param>
        /// <param name="nameIdFormat">The nameid format.</param>
        public void PerformQuery(HttpContext context, IDPEndPoint endPoint, string nameIdFormat)
        {
            Trace.TraceMethodCalled(GetType(), "PerformQuery()");

            HttpSOAPBindingBuilder builder = new HttpSOAPBindingBuilder(context);

            NameID name = new NameID();

            name.Value  = Saml20Identity.Current.Name;
            name.Format = nameIdFormat;
            _attrQuery.Subject.Items = new object[] { name };

            _attrQuery.SamlAttribute = _attributes.ToArray();
            XmlDocument query = new XmlDocument();

            query.XmlResolver = null;
            query.LoadXml(Serialization.SerializeToXmlString(_attrQuery));

            XmlSignatureUtils.SignDocument(query, ID);
            if (query.FirstChild is XmlDeclaration)
            {
                query.RemoveChild(query.FirstChild);
            }

            Stream s;

            if (Trace.ShouldTrace(TraceEventType.Information))
            {
                Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendAttrQuery, endPoint.metadata.GetAttributeQueryEndpointLocation(), query.OuterXml));
            }

            try
            {
                s = builder.GetResponse(endPoint.metadata.GetAttributeQueryEndpointLocation(), query.OuterXml,
                                        endPoint.AttributeQuery);
            }
            catch (Exception e)
            {
                Trace.TraceData(TraceEventType.Error, e.ToString());
                throw;
            }

            HttpSOAPBindingParser parser = new HttpSOAPBindingParser(s);

            Status status = parser.GetStatus();

            if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success)
            {
                Trace.TraceData(TraceEventType.Error,
                                string.Format(Tracing.AttrQueryStatusError, Serialization.SerializeToXmlString(status)));
                throw new Saml20Exception(status.StatusMessage);
            }

            bool isEncrypted;

            XmlElement xmlAssertion = Saml20SignonHandler.GetAssertion(parser.SamlMessage, out isEncrypted);

            if (isEncrypted)
            {
                Saml20EncryptedAssertion ass =
                    new Saml20EncryptedAssertion(
                        (RSA)FederationConfig.GetConfig().SigningCertificate.GetCertificate().PrivateKey);
                ass.LoadXml(xmlAssertion);
                ass.Decrypt();
                xmlAssertion = ass.Assertion.DocumentElement;
            }

            Saml20Assertion assertion =
                new Saml20Assertion(xmlAssertion, null,
                                    AssertionProfile.Core, endPoint.QuirksMode);

            if (Trace.ShouldTrace(TraceEventType.Information))
            {
                Trace.TraceData(TraceEventType.Information, string.Format(Tracing.AttrQueryAssertion, xmlAssertion == null ? string.Empty : xmlAssertion.OuterXml));
            }

            if (!assertion.CheckSignature(Saml20SignonHandler.GetTrustedSigners(endPoint.metadata.Keys, endPoint)))
            {
                Trace.TraceData(TraceEventType.Error, Resources.SignatureInvalid);
                throw new Saml20Exception(Resources.SignatureInvalid);
            }

            foreach (SamlAttribute attr in assertion.Attributes)
            {
                Saml20Identity.Current.AddAttributeFromQuery(attr.Name, attr);
            }
        }