public void PingTest_02() { string s = "https://adler.safewhere.local:9031/idp/SSO.saml2?SAMLRequest=7b0HYBxJliUmL23Ke39K9UrX4HShCIBgEyTYkEAQ7MGIzeaS7B1pRyMpqyqBymVWZV1mFkDM7Z28995777333nvvvfe6O51OJ%2fff%2fz9cZmQBbPbOStrJniGAqsgfP358Hz8iHv8e7xZlepnXTVEtP%2ftod7zz0e9x9Bsnj3%2fR7qPjdTtfvsp%2f0Tpv2vTs6WcfFbP7ew8fPnhw%2f97%2bZC%2fbvzebPty59%2bn92b37kwc755O9g92P0p80kPYIUnrWNOv8bNm02bKlj3Z2DrZ37m3v7L%2fZ3X90b%2ffRvU%2fHDz69v%2fPw3t5PfZQSHsvm0S%2fa%2feyjdb18VGVN0TxaZou8edROH70%2b%2fuL5IwL5aFVXbTWtyo8IyTR9zB3U8u7mF7OmyeuWUPvoCM2%2bnRVv14%2fvyvsC66Razgq0aN4THt6m94%2fXsyJfTvNXRK%2b6mOI7%2fcr70u%2fcfqYA7AddCI%2fvOtwwOXc7s3P0%2fwA%3d&SigAlg=http%3a%2f%2fwww.w3.org%2f2000%2f09%2fxmldsig%23rsa-sha1&Signature=UsZV%2bFga0YfCQaozLomKfV8jyNt85GMIYLFoBA9jrwFfabL%2bpAWVmlhwHyAMv50uxJWFc57v2ySj5Pc6e1t0NyyaguRL8VOKqB4P3svXV5U4iU0Gq4Rp1SJu0bj538%2f01X8IINmcAJMLdrx1cqCoRmofEcPPoQODWhQoq%2brjZdE%3d"; Uri url = new Uri(s); HttpRedirectBindingParser parser = new HttpRedirectBindingParser(url); X509Certificate2 cert = new X509Certificate2(@"Saml20\Certificates\SafewhereTest_SFS.pfx", "test1234"); Assert.That(parser.CheckSignature(cert.PublicKey.Key)); }
public override void ProcessRequest(HttpContext context) { if (context.Request.RequestType == "GET") { if (context.Request.Params["SAMLRequest"] == null) return; HttpRedirectBindingParser parser = new HttpRedirectBindingParser(context.Request.Url); Signin(parser); } // Not playing SAML2-Redirect-binding? You're on your own.... }
public void PingTest_01() { // Actual URL from Ping. string s = "http://haiku.safewhere.local/Saml20TestWeb/SSOLogout.saml2.aspx?SAMLResponse=fZFRa8IwEMe%2FSsm7bZq2qMEWZN1DwSEY0eGLpGmqZTUpuYTpt19bGVMYPob7%2FX%2BXu1sAv7QdXemTdnYjodMKpJdLsI3ittEqRWdrOxoEZ958OR94Lb%2FP0ki%2F1YK3AevjBG97fi%2FLgLH13eQPWuJz6K7IK9SveKtT1FQ1qYSoSSRIVMVhPJ3hpMQRj6IwKUVcJn0CwMlCgeXKpohgPJvgaILjbUhoQmg49cl8dui5PEWH%2BoaB6P2arAtlq%2FqWF%2FNTXn8y3yBvJw2MQxAfI%2B96aRXQceIUOaOo5tAAVfwigVpB2fJjRXuSdkZbLXSLssVA0%2FE%2F5iH%2FOs4BpBmWh7JlvnrfHIcKwcciXwQPvru8o8xy6%2BD59aYr6e146%2BTrVjDSlDkhJAAKsnuHP2nw34GzHw%3D%3D&SigAlg=http%3A%2F%2Fwww.w3.org%2F2000%2F09%2Fxmldsig%23rsa-sha1&Signature=UoYGLeSCYOSvjIaBpTcgtq2O0Nbz%2BVk%2BaaLESje8%2FZKxGNmWrFXJjSPrA403J23NeQzbxxVgOwSP8idIM95BhlVwxpiG%2B7%2FhJyNNrjGPohmD3cQpBWoWqZ8IEudDc%2FwDCshPb6wTdr6%2FOdKXQ2uwSK5NA2LYI8AAN5sq9kPtVvk%3D"; Uri url = new Uri(s); HttpRedirectBindingParser parser = new HttpRedirectBindingParser(url); X509Certificate2 cert = new X509Certificate2(@"Saml20\Certificates\pingcertificate.crt"); Assert.That(parser.CheckSignature(cert.PublicKey.Key)); }
/// <summary> /// Processes the request. /// </summary> /// <param name="context">The context.</param> public override void ProcessRequest(HttpContext context) { if (context.Request.HttpMethod != "GET") return; // Only handle Redirect logouts. HttpRedirectBindingParser parser = new HttpRedirectBindingParser(context.Request.Url); if (context.Request.Params["SAMLRequest"] != null) { HandleLogoutRequest(parser); } if (context.Request.Params["SAMLResponse"] != null) { HandleLogoutResponse(parser); } }
/// <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; }
/// <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"); }
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 TestDSASigning() { HttpRedirectBindingBuilder binding = new HttpRedirectBindingBuilder(); DSACryptoServiceProvider key = new DSACryptoServiceProvider(); binding.signingKey = key; binding.Request = string.Empty.PadLeft(500, 'a'); // Now, parse the query. Uri url = new Uri("http://localhost/?" + binding.ToQuery()); HttpRedirectBindingParser parser = new HttpRedirectBindingParser(url); Assert.That(parser.IsSigned); Assert.That(parser.IsRequest); Assert.That(parser.CheckSignature(key)); // Create a new key set, and check that it can not verify the signature. DSACryptoServiceProvider evilKey = new DSACryptoServiceProvider(); Assert.IsFalse(parser.CheckSignature(evilKey)); }
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 TestParsing_02() { HttpRedirectBindingBuilder bindingBuilder = new HttpRedirectBindingBuilder(); string request = string.Empty.PadRight(140, 'l'); string relaystate = "A relaystate test. @@@!!!&&&///"; bindingBuilder.Request = request; bindingBuilder.RelayState = relaystate; string query = bindingBuilder.ToQuery(); NameValueCollection coll = QueryToNameValueCollection(query); Assert.AreEqual(2, coll.Count); Uri url = new Uri("http://localhost/?" + query); HttpRedirectBindingParser bindingParser = new HttpRedirectBindingParser(url); Assert.IsTrue(bindingParser.IsRequest); Assert.IsFalse(bindingParser.IsResponse); Assert.IsFalse(bindingParser.IsSigned); Assert.IsNotNull(bindingParser.RelayState ); Assert.AreEqual(relaystate, bindingParser.RelayStateDecoded); Assert.AreEqual(request, bindingParser.Message); }
public void TestParsing_01() { HttpRedirectBindingBuilder bindingBuilder = new HttpRedirectBindingBuilder(); string request = string.Empty.PadLeft(350, 'A'); bindingBuilder.Request = request; string query = bindingBuilder.ToQuery(); NameValueCollection coll = QueryToNameValueCollection(query); Assert.That(coll.Count == 1); Uri url = new Uri("http://localhost/?" + query); HttpRedirectBindingParser bindingParser = new HttpRedirectBindingParser(url); Assert.That(bindingParser.IsRequest); Assert.That(!bindingParser.IsResponse); Assert.That(!bindingParser.IsSigned); Assert.AreEqual(request, bindingParser.Message); try { bindingParser.CheckSignature(new RSACryptoServiceProvider()); Assert.Fail("Trying to verify signature of an unsigned request should have thrown an exception."); } catch(InvalidOperationException) {} }
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; } }
private void HandleResponse(HttpContext context) { Trace.TraceMethodCalled(GetType(), "HandleResponse()"); string message = string.Empty; if(context.Request.RequestType == "GET") { HttpRedirectBindingParser parser = new HttpRedirectBindingParser(context.Request.Url); LogoutResponse response = Serialization.DeserializeFromXmlString<LogoutResponse>(parser.Message); IDPEndPoint idp = RetrieveIDPConfiguration(response.Issuer.Value); AuditLogging.IdpId = idp.Id; AuditLogging.AssertionId = response.ID; if (idp.metadata == null) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTRESPONSE, string.Format("No IDP metadata, unknown IDP, response: {0}", parser.Message)); HandleError(context, Resources.UnknownIDP); return; } if (!parser.VerifySignature(idp.metadata.Keys)) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTRESPONSE, string.Format("Invalid signature in redirect-binding, response: {0}", parser.Message)); HandleError(context, Resources.SignatureInvalid); return; } message = parser.Message; }else if(context.Request.RequestType == "POST") { HttpPostBindingParser parser = new HttpPostBindingParser(context); LogoutResponse response = Serialization.DeserializeFromXmlString<LogoutResponse>(parser.Message); IDPEndPoint idp = RetrieveIDPConfiguration(response.Issuer.Value); if (idp.metadata == null) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTRESPONSE, string.Format("No IDP metadata, unknown IDP, response: {0}", parser.Message)); HandleError(context, Resources.UnknownIDP); return; } if (!parser.IsSigned()) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTRESPONSE, string.Format("Signature not present, response: {0}", parser.Message)); HandleError(context, Resources.SignatureNotPresent); } // signature on final message in logout if (!parser.CheckSignature(idp.metadata.Keys)) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTRESPONSE, string.Format("Invalid signature in post-binding, response: {0}", parser.Message)); HandleError(context, Resources.SignatureInvalid); } message = parser.Message; }else { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTRESPONSE, string.Format("Unsupported request type format, type: {0}", context.Request.RequestType)); HandleError(context, Resources.UnsupportedRequestTypeFormat(context.Request.RequestType)); } AuditLogging.logEntry(Direction.IN, Operation.LOGOUTRESPONSE, message); XmlDocument doc = new XmlDocument(); doc.PreserveWhitespace = true; doc.LoadXml(message); XmlElement statElem = (XmlElement)doc.GetElementsByTagName(Status.ELEMENT_NAME, Saml20Constants.PROTOCOL)[0]; Status status = Serialization.DeserializeFromXmlString<Status>(statElem.OuterXml); if (status.StatusCode.Value != Saml20Constants.StatusCodes.Success) { AuditLogging.logEntry(Direction.IN, Operation.LOGOUTRESPONSE, string.Format("Unexpected status code: {0}, msg: {1}", status.StatusCode.Value, message)); HandleError(context, status); return; } AuditLogging.logEntry(Direction.IN, Operation.LOGOUTRESPONSE, "Assertion validated succesfully"); //Log the user out locally DoLogout(context); }