public void TestIntegrity_02() { HttpRedirectBindingBuilder binding = new HttpRedirectBindingBuilder(); binding.Response = "Response"; try { binding.Request = "Request"; Assert.Fail("HttpRedirectBinding did not throw an exception when both Request and Response were set."); } catch(ArgumentException) { } }
/// <summary> /// Transfers the message to the given endpoint using the HTTP-Redirect binding. /// </summary> protected static void HTTPRedirect(SAMLAction action, IDPEndPointElement endpoint, XmlNode message) { if (message.FirstChild is XmlDeclaration) message.RemoveChild(message.FirstChild); HttpRedirectBindingBuilder builder = new HttpRedirectBindingBuilder(); if (action == SAMLAction.SAMLRequest) builder.Request = message.OuterXml; else builder.Response = message.OuterXml; builder.signingKey = IDPConfig.IDPCertificate.PrivateKey; UriBuilder url = new UriBuilder(endpoint.Url); url.Query = builder.ToQuery(); HttpContext.Current.Response.Redirect(url.ToString(), true); }
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)); }
/// <summary> /// Initializes a new instance of the <see cref="Symplified.Auth.Saml20Authenticator"/> class. /// </summary> /// <param name="spName">Service Provider name.</param> /// <param name="idpMetadata">Identity Provider metadata.</param> public Saml20Authenticator (string spName, Saml20MetadataDocument idpMetadata) : base (PLACEHOLDER_URI, PLACEHOLDER_URI) { _spName = (string.IsNullOrEmpty (spName)) ? "symplified-mobile-sp" : spName; _idpMetadata = idpMetadata; var url = _idpMetadata.SSOEndpoint (SAMLBinding.POST).Url; var separator = url.Contains ("?") ? "&" : "?"; var authnRequest = Saml20AuthnRequest.GetDefault (_spName); var builder = new HttpRedirectBindingBuilder (); builder.Request = authnRequest.GetXml ().OuterXml; initialUrl = new Uri ( String.Format ( "{0}{1}{2}", url, separator, builder.ToQuery() ) ); }
private void TransferClient(IDPEndPoint idpEndpoint, Saml20AuthnRequest request, HttpContext context) { AuditLogging.AssertionId = request.ID; AuditLogging.IdpId = idpEndpoint.Id; //Set the last IDP we attempted to login at. context.Session[IDPTempSessionKey]= idpEndpoint.Id; // Determine which endpoint to use from the configuration file or the endpoint metadata. IDPEndPointElement destination = DetermineEndpointConfiguration(SAMLBinding.REDIRECT, idpEndpoint.SSOEndpoint, idpEndpoint.metadata.SSOEndpoints()); request.Destination = destination.Url; if (idpEndpoint.ForceAuthn) request.ForceAuthn = true; object isPassiveFlag = context.Session[IDPIsPassive]; if (isPassiveFlag != null && (bool)isPassiveFlag) { request.IsPassive = true; context.Session[IDPIsPassive] = null; } if (idpEndpoint.IsPassive) request.IsPassive = true; object forceAuthnFlag = context.Session[IDPForceAuthn]; if (forceAuthnFlag != null && (bool)forceAuthnFlag) { request.ForceAuthn = true; context.Session[IDPForceAuthn] = null; } if (idpEndpoint.SSOEndpoint != null) { if (!string.IsNullOrEmpty(idpEndpoint.SSOEndpoint.ForceProtocolBinding)) { request.ProtocolBinding = idpEndpoint.SSOEndpoint.ForceProtocolBinding; } } //Save request message id to session context.Session.Add(ExpectedInResponseToSessionKey, request.ID); if (destination.Binding == SAMLBinding.REDIRECT) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendAuthnRequest, Saml20Constants.ProtocolBindings.HTTP_Redirect, idpEndpoint.Id)); HttpRedirectBindingBuilder builder = new HttpRedirectBindingBuilder(); builder.signingKey = _certificate.PrivateKey; builder.Request = request.GetXml().OuterXml; string s = request.Destination + "?" + builder.ToQuery(); AuditLogging.logEntry(Direction.OUT, Operation.AUTHNREQUEST_REDIRECT, "Redirecting user to IdP for authentication", builder.Request); context.Response.Redirect(s, true); return; } if (destination.Binding == SAMLBinding.POST) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendAuthnRequest, Saml20Constants.ProtocolBindings.HTTP_Post, idpEndpoint.Id)); HttpPostBindingBuilder builder = 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.HTTP_Post; XmlDocument req = request.GetXml(); XmlSignatureUtils.SignDocument(req, request.ID); builder.Request = req.OuterXml; AuditLogging.logEntry(Direction.OUT, Operation.AUTHNREQUEST_POST); builder.GetPage().ProcessRequest(context); return; } if(destination.Binding == SAMLBinding.ARTIFACT) { Trace.TraceData(TraceEventType.Information, string.Format(Tracing.SendAuthnRequest, Saml20Constants.ProtocolBindings.HTTP_Artifact, idpEndpoint.Id)); HttpArtifactBindingBuilder builder = 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.HTTP_Artifact; AuditLogging.logEntry(Direction.OUT, Operation.AUTHNREQUEST_REDIRECT_ARTIFACT); builder.RedirectFromLogin(destination, request); } HandleError(context, Resources.BindingError); }
public void TestRelaystate_02() { HttpRedirectBindingBuilder bindingBuilder = new HttpRedirectBindingBuilder(); bindingBuilder.Response = "A random response... !!!! .... "; string relaystate = string.Empty.PadRight(10, 'A'); bindingBuilder.RelayState = relaystate; // When using the builder to create a response, the relaystate // should not be encoded, and can thus be located in the query-string string query = bindingBuilder.ToQuery(); Assert.That(query.Contains(relaystate)); }
public void TestRelaystate_01() { HttpRedirectBindingBuilder bindingBuilder = new HttpRedirectBindingBuilder(); bindingBuilder.Request = "A random request... !!!! .... "; string relaystate = string.Empty.PadRight(10, 'A'); bindingBuilder.RelayState = relaystate; // When using the builder to create a request, the relaystate should be encoded. string query = bindingBuilder.ToQuery(); Assert.That(!query.Contains(relaystate)); }
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 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.User.Identity.Name; 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.User.Identity.Name; 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.User.Identity.Name; 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); }