public void SignatureFinalRequestTest() { // Arrange var rtsSoapMessageSigned = XDocument.Load(@"Resources\Request25022015.xml"); var cert = new X509Certificate2(Convert.FromBase64String("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")); // Act var verified = XmlSignatureUtils.VerifySignature(rtsSoapMessageSigned, cert); // Assert Assert.IsTrue(verified); }
public void SignatureResponseTest() { // Arrange var rtsrSoapMessageSigned = XDocument.Load(@"Resources\Response25022015.xml"); var cert = new X509Certificate2(Convert.FromBase64String("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")); // Act var verified = XmlSignatureUtils.VerifySignature(rtsrSoapMessageSigned, cert); // Assert Assert.IsTrue(verified); }
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)); }
public void ModifyMessageAccordingToWsTrust(ref Message response, X509Certificate2 stsCertificate) { // Convert Message into a XML document that can be manipulated var xDocument = ConvertMessageToXml(response); // Log RSTR before being manipulated Logger.Instance.Trace("RSTR recieved from STS before being manipulated:\n" + xDocument); // SOAP 1.1 faults from NemLog-in STS contains two Envelope elements. This hack removes the first element whereafter the .Net framework will see it as a fault. RemoveOuterEnvelopeElementIfMessageIsASoapFault(ref xDocument, ref response); // Fault response is not SOAP 1.1 compliant. We therefore need to change it so that other channels (e.g. WSTrust channel) are able to read it properly. if (response.IsFault) { // Remove default namespace in order for fault message to be soap 1.1 compliant. var namespaceManager = new XmlNamespaceManager(new NameTable()); namespaceManager.AddNamespace("s", S11Namespace); namespaceManager.AddNamespace("wst", Wst13Namespace); var envelopeElement = xDocument.XPathSelectElement("/s:Envelope", namespaceManager); var xmlnsAttribute = envelopeElement.Attribute(XName.Get("xmlns")); xmlnsAttribute.Remove(); // faultcode must contain a qualified name. However, NemLog-in has forgotten to specify the wst namespace in order to make the SOAP fault SOAP 1.1 compliant. var xmlnsWstAttribute = envelopeElement.Attribute(XNamespace.Xmlns + Wst13Prefix); if (xmlnsWstAttribute == null) { envelopeElement.Add(new XAttribute(XNamespace.Xmlns + Wst13Prefix, Wst13Namespace)); } // faultcode and faultstring must be in the empty namespace. var faultElement = xDocument.XPathSelectElement("/s:Envelope/s:Body/s:Fault", namespaceManager); var faultcodeElement = xDocument.XPathSelectElement("/s:Envelope/s:Body/s:Fault/wst:faultcode", namespaceManager); faultcodeElement.Remove(); var faultstringElement = xDocument.XPathSelectElement("/s:Envelope/s:Body/s:Fault/wst:faultstring", namespaceManager); faultstringElement.Remove(); var newFaultCodeElement = new XElement("faultcode") { Value = faultcodeElement.Value }; var newFaultStringElement = new XElement("faultstring") { Value = faultstringElement.Value }; faultElement.Add(newFaultCodeElement); faultElement.Add(newFaultStringElement); } // Normal RSTR else { var namespaceManager = new XmlNamespaceManager(new NameTable()); namespaceManager.AddNamespace("s", S11Namespace); namespaceManager.AddNamespace("wsse", Wsse10Namespace); namespaceManager.AddNamespace("wsu", WsuNamespace); namespaceManager.AddNamespace("wst", Wst13Namespace); namespaceManager.AddNamespace("d", XmlDigSigNamespace); namespaceManager.AddNamespace("wsa", WsaNamespace); // Verify signature before making any modifications if (!XmlSignatureUtils.VerifySignature(xDocument, stsCertificate)) { throw new InvalidOperationException("SOAP signature recieved from STS does not validate!"); } // Expiry time is currently not on the format specified by the spec. The spec says yyyy-MM-ddTHH:mm:ssZ but yyyy-MM-ddTHH:mm:ss.fffZ is currently retrieved. // Verify life time of SOAP message var messageExpireTimeElement = xDocument.XPathSelectElement("/s:Envelope/s:Header/wsse:Security/wsu:Timestamp/wsu:Expires", namespaceManager); var messageExpireZuluTime = GetPatchedDateTime(messageExpireTimeElement.Value); var currentZuluTime = DateTime.UtcNow; if (currentZuluTime >= messageExpireZuluTime) { throw new InvalidOperationException("SOAP message has expired. Current Zulu time was: " + currentZuluTime + ", message Zulu expiry time was: " + messageExpireZuluTime); } // Verify life time of RSTS var rstsExpireTimeElement = xDocument.XPathSelectElement("/s:Envelope/s:Body/wst:RequestSecurityTokenResponseCollection/wst:RequestSecurityTokenResponse/wst:Lifetime/wsu:Expires", namespaceManager); var rstsExpireZuluTime = GetPatchedDateTime(rstsExpireTimeElement.Value); if (currentZuluTime >= rstsExpireZuluTime) { throw new InvalidOperationException("RSTS has expired. Current Zulu time was: " + currentZuluTime + ", RSTS Zulu expiry time was: " + rstsExpireZuluTime); } // Verify replay attack var signatureValueElement = xDocument.XPathSelectElement("/s:Envelope/s:Header/wsse:Security/d:Signature/d:SignatureValue", namespaceManager); if (ReplyAttackCache.DoesKeyExist(signatureValueElement.Value)) { var messageIdElement = xDocument.XPathSelectElement("/s:Envelope/s:Header/wsa:MessageID", namespaceManager); throw new InvalidOperationException("Replay attack detected. Response message id: " + messageIdElement.Value); } else { ReplyAttackCache.Set(signatureValueElement.Value, messageExpireZuluTime); } // response is validated ok ManipulateRstrBody(xDocument); } // Log RSTR before being manipulated Logger.Instance.Trace("RSTR recieved from STS after being manipulated:\n" + xDocument); // Convert XML back to a Message response = ConvertXmlToMessage(response, xDocument); // The Security element is only present in succesfull responses. if (!response.IsFault) { // Security header element is marked with the MustUnderstand attribute. Hence, we need to inform the WCF framework that this header element has been taken care of. response.Headers.UnderstoodHeaders.Add( response.Headers.Single(x => "Security" == x.Name && Wsse10Namespace == x.Namespace)); } }
public new void ProcessRequest(HttpContext context) { try { // ***** RESPONSE ***** if (!String.IsNullOrEmpty(context.Request[HttpBindingConstants.SAMLResponse])) { // Recupera Response string samlresponse = context.Request[HttpBindingConstants.SAMLResponse]; XmlDocument doc = new XmlDocument(); doc.PreserveWhitespace = true; doc.LoadXml(samlresponse); // Verifica Signature do Response if (XmlSignatureUtils.VerifySignature(doc)) { SAMLResponse = SAMLUtility.DeserializeFromXmlString <ResponseType>(doc.InnerXml); if (SAMLResponse.Items.Length > 0) { for (int i = 0; i < SAMLResponse.Items.Length; i++) { if (SAMLResponse.Items[i] is AssertionType) { NameIDType nameID = null; AssertionType assertion = (AssertionType)SAMLResponse.Items[i]; for (int j = 0; j < assertion.Subject.Items.Length; j++) { if (assertion.Subject.Items[j] is NameIDType) { nameID = (NameIDType)assertion.Subject.Items[j]; } } if (nameID != null) { SignHelper.AutenticarUsuarioDaRespostaDoSaml(nameID.Value); } } // Armazena dados do sistema emissor do Request // em Cookie de sistemas autenticados AddSAMLCookie(context); } } context.Response.Redirect(HttpUtility.UrlDecode(context.Request[HttpBindingConstants.RelayState]), false); } else { throw new ValidationException("Não foi possível encontrar assinatura."); } } // ***** REQUEST ***** else if (!String.IsNullOrEmpty(context.Request[HttpBindingConstants.SAMLRequest])) { throw new NotImplementedException(); } else { // Carrega as configurações do ServiceProvider ServiceProvider config = ServiceProvider.GetConfig(); ServiceProviderEndpoint spend = SAMLUtility.GetServiceProviderEndpoint(config.ServiceEndpoint, SAMLTypeSSO.signon); // Verifica configuração do ServiceProvider para signon if (spend == null) { throw new ValidationException("Não foi possível encontrar as configurações do ServiceProvider para signon."); } // Verifica se usuário está autenticado, caso não envia um Resquest solicitando autenticação if (!UsuarioWebIsValid()) { SAMLRequest = new SAMLAuthnRequest(); SAMLRequest.Issuer = config.id; SAMLRequest.AssertionConsumerServiceURL = context.Request.Url.AbsoluteUri; HttpRedirectBinding binding = new HttpRedirectBinding(SAMLRequest, spend.localpath); binding.SendRequest(context, spend.redirectUrl); } else { HttpContext.Current.Response.Redirect(spend.localpath, false); HttpContext.Current.ApplicationInstance.CompleteRequest(); } } } catch (ValidationException ex) { ErrorMessage(ex.Message); } catch (Exception ex) { ApplicationWEB._GravaErro(ex); ErrorMessage("Não foi possível atender a solicitação."); } }