private void CreateMetadataDocument(HttpContext context, bool sign)
        {
            SAML20FederationConfig configuration = ConfigurationReader.GetConfig<SAML20FederationConfig>();

            KeyInfo keyinfo = new KeyInfo();
            KeyInfoX509Data keyClause = new KeyInfoX509Data(ConfigurationReader.GetConfig<FederationConfig>().SigningCertificate.GetCertificate(), X509IncludeOption.EndCertOnly);
            keyinfo.AddClause(keyClause);

            Saml20MetadataDocument doc = new Saml20MetadataDocument(configuration, keyinfo, sign);

            context.Response.Write(doc.ToXml( context.Response.ContentEncoding ));
        }
            public void CanExtractEndpoints()
            {
                // Arrange
                var doc = new XmlDocument { PreserveWhitespace = true };
                doc.Load(@"Protocol\MetadataDocs\metadata-ADLER.xml");

                // Act
                var metadata = new Saml20MetadataDocument(doc);

                // Assert
                Assert.AreEqual(2, metadata.IDPSLOEndpoints.Count);
                Assert.AreEqual(2, metadata.SSOEndpoints.Count);
            }
示例#3
0
        /// <summary>
        /// Creates the metadata document.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="sign">if set to <c>true</c> sign the document.</param>
        public string CreateMetadataDocument(Encoding encoding, bool sign)
        {
            logger.Debug(TraceMessages.MetadataDocumentBeingCreated);

            var keyinfo = new System.Security.Cryptography.Xml.KeyInfo();
            var keyClause = new System.Security.Cryptography.Xml.KeyInfoX509Data(configuration.ServiceProvider.SigningCertificate, X509IncludeOption.EndCertOnly);
            keyinfo.AddClause(keyClause);

            var doc = new Saml20MetadataDocument(configuration, keyinfo, sign);

            logger.Debug(TraceMessages.MetadataDocumentCreated);
            return doc.ToXml(encoding, configuration.ServiceProvider.SigningCertificate);
        }
        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();
        }
示例#5
0
        /// <summary>
        /// Verify the request and transfer the login-page.
        /// </summary>
        /// <param name="parser"></param>
        private static void Signin(HttpRedirectBindingParser parser)
        {
            AuthnRequest req = Serialization.DeserializeFromXmlString <AuthnRequest>(parser.Message);

            // Retrieve metadata of requestor.
            string SPID = req.Issuer.Value;
            Saml20MetadataDocument SPmetadata = GetMetadata(SPID);

            if (parser.IsSigned && !CheckRedirectSignature(parser, SPmetadata))
            {
                HandleUnableToVerifySignature(SPID);
                return;
            }

            HttpContext.Current.Application["authenticationrequest"] = req;
            HttpContext.Current.Server.Transfer("SignonForm.aspx");
        }
示例#6
0
        /// <summary>
        /// Creates the metadata document.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="sign">if set to <c>true</c> sign the document.</param>
        private void CreateMetadataDocument(HttpContext context, bool sign)
        {
            Logger.Debug(TraceMessages.MetadataDocumentBeingCreated);

            var configuration = Saml2Config.GetConfig();

            var keyinfo   = new KeyInfo();
            var keyClause = new KeyInfoX509Data(Saml2Config.GetConfig().ServiceProvider.SigningCertificate.GetCertificate(), X509IncludeOption.EndCertOnly);

            keyinfo.AddClause(keyClause);

            var doc = new Saml20MetadataDocument(configuration, keyinfo, sign);

            Logger.Debug(TraceMessages.MetadataDocumentCreated);

            context.Response.Write(doc.ToXml(context.Response.ContentEncoding));
        }
        public void AddByMetadataUrl(Uri url)
        {
            var request = System.Net.WebRequest.Create(url);

            // It may be more efficient to pass the stream directly, but
            // it's likely a bit safer to pull the data off the response
            // stream and create a new memorystream with the data
            using (var ms = new MemoryStream()) {
                using (var response = request.GetResponse().GetResponseStream()) {
                    response.CopyTo(ms);
                    response.Close();
                }
                ms.Seek(0, SeekOrigin.Begin); // Rewind memorystream back to the beginning
                // We want to allow exceptions to bubble up in this case
                var metadataDoc = new Saml20MetadataDocument(ms, GetEncodings());
                AdjustIdpListWithNewMetadata(metadataDoc);
            }
        }
示例#8
0
        private void CreateMetadataDocument(HttpContext context, bool sign)
        {
            SAML20FederationConfig configuration = SAML20FederationConfig.GetConfig();

            var keyinfos = new List <KeyInfo>();

            foreach (Certificate certificate in FederationConfig.GetConfig().SigningCertificates)
            {
                KeyInfo         keyinfo   = new KeyInfo();
                KeyInfoX509Data keyClause = new KeyInfoX509Data(certificate.GetCertificate(), X509IncludeOption.EndCertOnly);
                keyinfo.AddClause(keyClause);
                keyinfos.Add(keyinfo);
            }

            Saml20MetadataDocument doc = new Saml20MetadataDocument(configuration, keyinfos, sign);

            context.Response.Write(doc.ToXml(context.Response.ContentEncoding));
        }
示例#9
0
        private static void HandleLogoutResponse(HttpRedirectBindingParser parser)
        {
            LogoutResponse res = Serialization.DeserializeFromXmlString <LogoutResponse>(parser.Message);

            // Retrieve metadata of requestor.
            string SPID = res.Issuer.Value;
            Saml20MetadataDocument SPmetadata = GetMetadata(SPID);

            if (parser.IsSigned && !CheckRedirectSignature(parser, SPmetadata))
            {
                HandleUnableToVerifySignature(SPID);
                return;
            }

            // Remove the Service Provider from the list of the user's active sessions.
            UserSessionsHandler.RemoveLoggedInSession(SPID);

            Logout();
        }
            public void SignsXml()
            {
                // Arrange
                var doc    = new Saml20MetadataDocument(true);
                var entity = doc.CreateDefaultEntity();

                entity.ValidUntil = DateTime.Now.AddDays(14);

                // Act
                var metadata = doc.ToXml();
                var document = new XmlDocument {
                    PreserveWhitespace = true
                };

                document.LoadXml(metadata);
                var result = XmlSignatureUtils.CheckSignature(document);

                // Assert
                Assert.That(result);
            }
示例#11
0
        private static void HandleLogoutRequest(HttpRedirectBindingParser parser)
        {
            LogoutRequest req = Serialization.DeserializeFromXmlString <LogoutRequest>(parser.Message);

            // Retrieve metadata of requestor.
            string SPID = req.Issuer.Value;
            Saml20MetadataDocument SPmetadata = GetMetadata(SPID);

            if (parser.IsSigned && !CheckRedirectSignature(parser, SPmetadata))
            {
                HandleUnableToVerifySignature(SPID);
                return;
            }

            // Set the entity ID of the federation partner that initiated the logout.
            HttpContext.Current.Session[LOGOUTINITIATORKEY] = SPID;
            UserSessionsHandler.RemoveLoggedInSession(SPID);

            Logout();
        }
            public void CanExtractCertificatesOnStream()
            {
                Saml20MetadataDocument metadata;
                // Arrange
                using (var ms = new MemoryStream()) {
                    using (var reader = File.OpenText(@"Protocol\MetadataDocs\metadata-ADLER.xml")) {
                        reader.BaseStream.CopyTo(ms);
                        reader.Close();
                    }
                    ms.Seek(0, SeekOrigin.Begin);
                    metadata = new Saml20MetadataDocument(ms, null);
                }

                // Assert
                Assert.That(metadata.GetKeys(KeyTypes.Signing).Count == 1);
                Assert.That(metadata.GetKeys(KeyTypes.Encryption).Count == 1);
                Assert.That(metadata.Keys[0].Use == KeyTypes.Signing);
                Assert.That(metadata.Keys[1].Use == KeyTypes.Encryption);

                Assert.AreEqual("ADLER_SAML20_ID", metadata.EntityId);
            }
示例#13
0
            public void SignsXml()
            {
                // Arrange
                var doc    = new Saml20MetadataDocument(true);
                var entity = doc.CreateDefaultEntity();

                entity.ValidUntil = DateTime.Now.AddDays(14);

                var certificate = new X509Certificate2(FileEmbeddedResource("SAML2.Tests.Certificates.sts_dev_certificate.pfx"), "test1234");
                // Act
                var metadata = doc.ToXml(null, certificate);
                var document = new XmlDocument {
                    PreserveWhitespace = true
                };

                document.LoadXml(metadata);
                var result = XmlSignatureUtils.CheckSignature(document);

                // Assert
                Assert.That(result);
            }
            public void CanExtractCertificatesOnStream()
            {
                Saml20MetadataDocument metadata;

                // Arrange
                using (var ms = new MemoryStream()) {
                    using (var reader = File.OpenText(@"Protocol\MetadataDocs\metadata-ADLER.xml")) {
                        reader.BaseStream.CopyTo(ms);
                        reader.Close();
                    }
                    ms.Seek(0, SeekOrigin.Begin);
                    metadata = new Saml20MetadataDocument(ms, null);
                }

                // Assert
                Assert.That(metadata.GetKeys(KeyTypes.Signing).Count == 1);
                Assert.That(metadata.GetKeys(KeyTypes.Encryption).Count == 1);
                Assert.That(metadata.Keys[0].Use == KeyTypes.Signing);
                Assert.That(metadata.Keys[1].Use == KeyTypes.Encryption);

                Assert.AreEqual("ADLER_SAML20_ID", metadata.EntityId);
            }
            public void CanExtractCertificates()
            {
                // Arrange
                var doc = new XmlDocument { PreserveWhitespace = true };
                doc.Load(@"Protocol\MetadataDocs\metadata-ADLER.xml");

                // Act
                var metadata = new Saml20MetadataDocument(doc);
                var certificateCheckResult = XmlSignatureUtils.CheckSignature(doc, (KeyInfo)metadata.Keys[0].KeyInfo);

                // Assert
                Assert.That(metadata.GetKeys(KeyTypes.Signing).Count == 1);
                Assert.That(metadata.GetKeys(KeyTypes.Encryption).Count == 1);
                Assert.That(metadata.Keys[0].Use == KeyTypes.Signing);
                Assert.That(metadata.Keys[1].Use == KeyTypes.Encryption);

                // The two certs in the metadata document happen to be identical, and are also
                // used for signing the entire document.
                // Extract the certificate and verify the document.
                Assert.That(certificateCheckResult);
                Assert.AreEqual("ADLER_SAML20_ID", metadata.EntityId);
            }
示例#16
0
        public void LoginWithIdentityProvider()
        {
            XmlDocument xDoc = new XmlDocument();

            xDoc.PreserveWhitespace = true;
            xDoc.Load("idp.symplified.net.metadata.xml");

            Saml20MetadataDocument idpMetadata = new Saml20MetadataDocument(xDoc);

            Saml20Authenticator authenticator = new Saml20Authenticator(
                "Symplified.Auth.iOS.Sample",
                idpMetadata
                );

            authenticator.Completed += (s, e) => {
                loginViewController.DismissViewController(true, null);

                if (!e.IsAuthenticated)
                {
                    samlLoginStatusStringElement.Caption = "Not authorized";
                    samlLoginStatusStringElement.GetActiveCell().BackgroundColor = UIColor.Red;
                }
                else
                {
                    SamlAccount authenticatedAccount = (SamlAccount)e.Account;

                    samlLoginStatusStringElement.Caption = String.Format("Name: {0}", authenticatedAccount.Assertion.Subject.Value);
                    samlLoginStatusStringElement.GetActiveCell().BackgroundColor = UIColor.Green;
                }

                loginViewController.ReloadData();
            };

            vc = authenticator.GetUI();
            loginViewController.PresentViewController(vc, true, null);
        }
示例#17
0
        /// <summary>
        /// Build a LogoutRequest and send it to the Federation Partner with the given entity ID.
        /// </summary>
        /// <param name="entityID"></param>
        private static void CreateLogoutRequest(string entityID)
        {
            User user = UserSessionsHandler.CurrentUser;

            Saml20LogoutRequest request = new Saml20LogoutRequest();

            request.Issuer       = IDPConfig.ServerBaseUrl;
            request.SessionIndex = Guid.NewGuid().ToString("N");

            request.SubjectToLogOut        = new NameID();
            request.SubjectToLogOut.Format = Saml20Constants.NameIdentifierFormats.Unspecified;
            request.SubjectToLogOut.Value  = user.Username;
            request.NotOnOrAfter           = DateTime.UtcNow.AddMinutes(5);

            Saml20MetadataDocument metadata = GetMetadata(entityID);

            // HTTPRedirect(SAMLAction.SAMLRequest, metadata.SLOEndpoint(SAMLBinding.REDIRECT), request.GetXml());


            HttpPostBindingBuilder builder = new HttpPostBindingBuilder(metadata.SLOEndpoint(SAMLBinding.POST));

            builder.Action = SAMLAction.SAMLRequest;
            //builder.Response = assertionDoc.OuterXml;

            string xmloutput = request.GetXml().OuterXml;

            TextWriter tw = new StreamWriter("C:\\temp\\idp.txt", true);

            tw.WriteLine(xmloutput);
            tw.Close();

            builder.Response = xmloutput;

            builder.GetPage().ProcessRequest(HttpContext.Current);
            HttpContext.Current.Response.End();
        }
示例#18
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);
            var         shaHashingAlgorithm = SignatureProviderFactory.ValidateShaHashingAlgorithm(idp.ShaHashingAlgorithm);

            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(idp, 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;
                    IDPEndPointElement destination =
                        DetermineEndpointConfiguration(SAMLBinding.REDIRECT, idp.SLOEndpoint, idp.metadata.SLOEndpoints());

                    builder.RedirectFromLogout(idp, 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));
                }

                Saml20LogoutResponse response = new Saml20LogoutResponse();

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

                if (idp.metadata == null)
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Cannot find metadata for IdP: " + parser.Issuer);
                    // Not able to process the request as we do not know the IdP.
                    response.StatusCode = Saml20Constants.StatusCodes.NoAvailableIDP;
                }
                else
                {
                    Saml20MetadataDocument metadata = idp.metadata;

                    if (!parser.CheckSignature(metadata.GetKeys(KeyTypes.signing)))
                    {
                        AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Request has been denied. Invalid signature SOAP logout, msg: " + parser.SamlMessage.OuterXml);
                        response.StatusCode = Saml20Constants.StatusCodes.RequestDenied;
                    }
                }

                if (parser.GetNameID() != null && !string.IsNullOrEmpty(parser.GetNameID().Value))
                {
                    DoSoapLogout(context, parser.GetNameID().Value);
                }
                else
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Request has been denied. No user ID was supplied in SOAP logout request, msg: " + parser.SamlMessage.OuterXml);
                    response.StatusCode = Saml20Constants.StatusCodes.NoAuthnContext;
                }

                LogoutRequest req = parser.LogoutRequest;

                //Build the response object
                response.Issuer       = config.ServiceProvider.ID;
                response.StatusCode   = Saml20Constants.StatusCodes.Success;
                response.InResponseTo = req.ID;
                XmlDocument doc = response.GetXml();
                var         signingCertificate = FederationConfig.GetConfig().SigningCertificate.GetCertificate();
                var         signatureProvider  = SignatureProviderFactory.CreateFromShaHashingAlgorithmName(shaHashingAlgorithm);
                signatureProvider.SignAssertion(doc, response.ID, signingCertificate);
                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));
                }
            }
        }
示例#19
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;
            }
        }
示例#20
0
 public void Parse_metadata_from_xml_test_idp()
 {
     var metadata = new Saml20MetadataDocument().Load(FileLoadUtils.GetStream(Path.Combine("Protocol", "MetadataDocs", "inlogik-test-adfs-metadata.xml")));
     var a        = metadata.EntityId;
 }
示例#21
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;

            var       nameIdFormat = metadataDocument.Entity.Items.OfType <SPSSODescriptor>().SingleOrDefault()?.NameIDFormat.SingleOrDefault() ?? Saml20Constants.NameIdentifierFormats.Persistent;
            Assertion assertion    = CreateAssertion(user, entityId, nameIdFormat);

            var signatureProvider = SignatureProviderFactory.CreateFromShaHashingAlgorithmName(ShaHashingAlgorithm.SHA256);
            EncryptedAssertion encryptedAssertion = null;

            var keyDescriptors = metadataDocument.Keys.Where(x => x.use == KeyTypes.encryption);

            if (keyDescriptors.Any())
            {
                foreach (KeyDescriptor keyDescriptor in keyDescriptors)
                {
                    KeyInfo ki = (KeyInfo)keyDescriptor.KeyInfo;

                    foreach (KeyInfoClause clause in ki)
                    {
                        if (clause is KeyInfoX509Data)
                        {
                            X509Certificate2 cert = XmlSignatureUtils.GetCertificateFromKeyInfo((KeyInfoX509Data)clause);

                            var    spec = new DefaultCertificateSpecification();
                            string error;
                            if (spec.IsSatisfiedBy(cert, out error))
                            {
                                AsymmetricAlgorithm key = XmlSignatureUtils.ExtractKey(clause);
                                AssertionEncryptionUtility.AssertionEncryptionUtility encryptedAssertionUtil = new AssertionEncryptionUtility.AssertionEncryptionUtility((RSA)key, assertion);

                                // Sign the assertion inside the response message.
                                signatureProvider.SignAssertion(encryptedAssertionUtil.Assertion, assertion.ID, IDPConfig.IDPCertificate);

                                encryptedAssertionUtil.Encrypt();
                                encryptedAssertion = Serialization.DeserializeFromXmlString <EncryptedAssertion>(encryptedAssertionUtil.EncryptedAssertion.OuterXml);
                                break;
                            }
                        }
                    }
                    if (encryptedAssertion != null)
                    {
                        break;
                    }
                }

                if (encryptedAssertion == null)
                {
                    throw new Exception("Could not encrypt. No valid certificates found.");
                }
            }

            if (encryptedAssertion != null)
            {
                response.Items = new object[] { encryptedAssertion };
            }
            else
            {
                response.Items = new object[] { assertion };
            }

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

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

            if (encryptedAssertion == null)
            {
                // Sign the assertion inside the response message.
                signatureProvider.SignAssertion(responseDoc, assertion.ID, IDPConfig.IDPCertificate);
            }

            HttpPostBindingBuilder builder = new HttpPostBindingBuilder(endpoint);

            builder.Action = SAMLAction.SAMLResponse;

            builder.Response = responseDoc.OuterXml;

            builder.GetPage().ProcessRequest(Context);
            Context.Response.End();
        }
        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;
                }

                if (logoutRequest.NotOnOrAfter.HasValue)
                {
                    var allowedClockSkewTime = DateTime.UtcNow.AddMinutes(FederationConfig.GetConfig().AllowedClockSkewMinutes);

                    if (logoutRequest.NotOnOrAfter >= allowedClockSkewTime)
                    {
                        var errormessage =
                            $"Logout request NotOnOrAfter ({logoutRequest.NotOnOrAfter}) is after allowed time ({allowedClockSkewTime})";
                        AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, errormessage);
                        HandleError(context, errormessage);
                        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, string.Format(Resources.UnsupportedRequestType, context.Request.RequestType));
                return;
            }

            AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, message);

            // Check that idp in session and request matches.
            string idpRequest = logoutRequest.Issuer.Value;

            // SessionFactory.SessionContext.Current.New is never the first call to Current due to the logic in Application_AuthenticateRequest() ... Saml20Identity.IsInitialized()
            // Hence we need to check on Saml20Identity.IsInitialized() instead of using SessionFactory.SessionContext.Current.New.
            bool isOioSamlSessionActive = Saml20Identity.IsInitialized();

            if (isOioSamlSessionActive)
            {
                object idpId = Saml20PrincipalCache.GetSaml20AssertionLite().Issuer;

                if (idpId != null && idpId.ToString() != idpRequest)
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, string.Format(Resources.IdPMismatchBetweenRequestAndSession, idpId, 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 && isOioSamlSessionActive)
            {
                // 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
            var shaHashingAlgorithm = SignatureProviderFactory.ValidateShaHashingAlgorithm(endpoint.ShaHashingAlgorithm);

            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;
                builder.ShaHashingAlgorithm = shaHashingAlgorithm;
                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();
                var         signingCertificate = FederationConfig.GetConfig().SigningCertificate.GetCertificate();
                var         signatureProvider  = SignatureProviderFactory.CreateFromShaHashingAlgorithmName(shaHashingAlgorithm);
                signatureProvider.SignAssertion(responseDocument, response.ID, signingCertificate);
                builder.Response   = responseDocument.OuterXml;
                builder.RelayState = context.Request.Params["RelayState"];
                builder.GetPage().ProcessRequest(context);
                return;
            }
        }
        /// <summary>
        /// Creates the metadata document.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="sign">if set to <c>true</c> sign the document.</param>
        private void CreateMetadataDocument(HttpContext context, bool sign)
        {
            Logger.Debug(TraceMessages.MetadataDocumentBeingCreated);

            var configuration = Saml2Config.GetConfig();

            var keyinfo = new KeyInfo();
            var keyClause = new KeyInfoX509Data(Saml2Config.GetConfig().ServiceProvider.SigningCertificate.GetCertificate(), X509IncludeOption.EndCertOnly);
            keyinfo.AddClause(keyClause);

            var doc = new Saml20MetadataDocument(configuration, keyinfo, sign);

            Logger.Debug(TraceMessages.MetadataDocumentCreated);

            context.Response.Write(doc.ToXml(context.Response.ContentEncoding));
        }
示例#24
0
        public void Serialize_metadata_to_xml_empty_constructor_should_throw_exception()
        {
            var metadata = new Saml20MetadataDocument();

            Assert.Throws <System.InvalidOperationException>(() => metadata.ToXml());
        }
            public void SignsXml()
            {
                // Arrange
                var doc = new Saml20MetadataDocument(true);
                var entity = doc.CreateDefaultEntity();
                entity.ValidUntil = DateTime.Now.AddDays(14);

                var certificate = new X509Certificate2(FileEmbeddedResource("SAML2.Tests.Certificates.sts_dev_certificate.pfx"), "test1234");
                // Act
                var metadata = doc.ToXml(null, certificate);
                var document = new XmlDocument { PreserveWhitespace = true };
                document.LoadXml(metadata);
                var result = XmlSignatureUtils.CheckSignature(document);

                // Assert
                Assert.That(result);
            }
示例#26
0
        /// <summary>
        /// Checks the signature of a message received using the redirect binding using the keys found in the
        /// metadata of the federation partner that sent the request.
        /// </summary>
        protected static bool CheckRedirectSignature(HttpRedirectBindingParser parser, Saml20MetadataDocument metadata)
        {
            List <KeyDescriptor> keys = metadata.GetKeys(KeyTypes.signing);

            // Go through the list of signing keys (usually only one) and use it to verify the REDIRECT request.
            foreach (KeyDescriptor key in keys)
            {
                KeyInfo keyinfo = (KeyInfo)key.KeyInfo;
                foreach (KeyInfoClause keyInfoClause in keyinfo)
                {
                    AsymmetricAlgorithm signatureKey = XmlSignatureUtils.ExtractKey(keyInfoClause);
                    if (signatureKey != null && parser.CheckSignature(signatureKey))
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
        private void HandleRequest(HttpContext context)
        {
            Trace.TraceMethodCalled(GetType(), "HandleRequest()");

            //Fetch the endpoint configuration
            IDPEndPoint idpEndpoint = RetrieveIDPConfiguration(context.Session[IDPLoginSessionKey].ToString());

            IDPEndPointElement destination =
                DetermineEndpointConfiguration(SAMLBinding.REDIRECT, idpEndpoint.SLOEndpoint, idpEndpoint.metadata.SLOEndpoints());

            //Fetch config object
            SAML20FederationConfig config = ConfigurationReader.GetConfig <SAML20FederationConfig>();

            //Build the response object
            Saml20LogoutResponse response = new Saml20LogoutResponse();

            response.Issuer      = config.ServiceProvider.ID;
            response.Destination = destination.Url;
            response.StatusCode  = Saml20Constants.StatusCodes.Success;

            string message = string.Empty;

            if (context.Request.RequestType == "GET") // HTTP Redirect binding
            {
                HttpRedirectBindingParser parser = new HttpRedirectBindingParser(context.Request.Url);
                IDPEndPoint endpoint             = config.FindEndPoint(idpEndpoint.Id);

                if (endpoint.metadata == null)
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Cannot find metadata for IdP");
                    HandleError(context, "Cannot find metadata for IdP " + idpEndpoint.Id);
                    return;
                }

                Saml20MetadataDocument metadata = endpoint.metadata;

                if (!parser.VerifySignature(metadata.GetKeys(KeyTypes.signing)))
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Invalid signature redirect-binding, msg: " + parser.Message);
                    HandleError(context, Resources.SignatureInvalid);
                    return;
                }

                message = parser.Message;
            }
            else if (context.Request.RequestType == "POST") // HTTP Post binding
            {
                HttpPostBindingParser parser = new HttpPostBindingParser(context);

                if (!parser.IsSigned())
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Signature not present, msg: " + parser.Message);
                    HandleError(context, Resources.SignatureNotPresent);
                }

                IDPEndPoint endpoint = config.FindEndPoint(idpEndpoint.Id);
                if (endpoint.metadata == null)
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Cannot find metadata for IdP");
                    HandleError(context, "Cannot find metadata for IdP " + idpEndpoint.Id);
                    return;
                }

                Saml20MetadataDocument metadata = endpoint.metadata;

                // handle a logout-request
                if (!parser.CheckSignature(metadata.GetKeys(KeyTypes.signing)))
                {
                    AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, "Invalid signature post-binding, msg: " + parser.Message);
                    HandleError(context, Resources.SignatureInvalid);
                }

                message = parser.Message;
            }
            else
            {
                //Error: We don't support HEAD, PUT, CONNECT, TRACE, DELETE and OPTIONS
                HandleError(context, Resources.UnsupportedRequestTypeFormat(context.Request.RequestType));
            }

            AuditLogging.logEntry(Direction.IN, Operation.LOGOUTREQUEST, message);

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

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

            response.InResponseTo = req.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;
            }
        }
示例#28
0
 public void Parse_metadata_from_xml()
 {
     var metadata = new Saml20MetadataDocument().Load(FileLoadUtils.GetStream(Path.Combine("Protocol", "MetadataDocs", "metadata-HAIKU.xml")));
 }
            public void SignsXml()
            {
                // Arrange
                var doc = new Saml20MetadataDocument(true);
                var entity = doc.CreateDefaultEntity();
                entity.ValidUntil = DateTime.Now.AddDays(14);

                // Act
                var metadata = doc.ToXml();
                var document = new XmlDocument { PreserveWhitespace = true };
                document.LoadXml(metadata);
                var result = XmlSignatureUtils.CheckSignature(document);

                // Assert
                Assert.That(result);
            }
示例#30
0
        public void Serialize_metatdata_from_configuration_not_signed()
        {
            var metadata = new Saml20MetadataDocument().Load(_context.Config);

            Assert.NotEmpty(metadata.ToXml());
        }