Używam klienta WCF do rozmawiania z usługą inną niż WCF.Określanie odniesienia URI #Body podczas cyfrowego podpisywania żądania SOAP - przy użyciu WCF
Ta usługa WWW wymaga podpisania treści komunikatu SOAP, ale mam problem z wygenerowaniem prawidłowego żądania SOAP.
Zaimplementowałem ClientMessageInspector, który dziedziczy po IClientMessageInspector, gdzie modyfikuję komunikat w metodzie BeforeSendRequest w celu dodania podpisu cyfrowego XML. W tym celu używam klasy SignedXML.
Używam narzędzia sprawdzania poprawności IBM Web Services dla WSDL i SOAP w celu sprawdzenia, czy mój podpis cyfrowy weryfikuje.
Mój problem polega na tym, że kiedy podaję referencje pełnego referencyjnego identyfikatora w referencyjnym identyfikatorze URI, narzędzia IBM, których używam, mówią, że mam prawidłowy podpis. Ze specyfikacji XML Digital Signature powinieneś móc odwoływać się do atrybutu bez przestrzeni nazw, jednak gdy to zrobię, nie otrzymam prawidłowego podpisu cyfrowego.
To żądanie SOAP Jestem obecnie generowania, co mówią moje narzędzia ma prawidłowy podpis, ale usługa internetowa nie podoba:
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing"
xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:soapsec="http://schemas.xmlsoap.org/soap/security/2000-12"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<s:Header>
<soapsec:Signature>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="http://schemas.xmlsoap.org/soap/security/2000-12#Body">
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>4mt5wluUTu5tpR2d5UemVSLvqTs=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>UZ7HzfE3GxIY9hg...</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>MIIEkTCCA3mgAwIBAgIQCu...</X509Certificate>
</X509Data>
<KeyValue>
<RSAKeyValue>
<Modulus>0C3e9HDx5Yq6FLUxIgjJ...</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
</KeyValue>
</KeyInfo>
</Signature>
</soapsec:Signature>
</s:Header>
<s:Body soapsec:id="Body">
.... SOAP Body Here ...
</s:Body>
</s:Envelope>
To żądanie SOAP Chcę być generowanie , ale moje narzędzia powiedzieć to ma nieprawidłowy podpis, a serwis internetowy mówi mi też podpis jest nieważny:
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing"
xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:soapsec="http://schemas.xmlsoap.org/soap/security/2000-12"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<s:Header>
<soapsec:Signature>
<Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
<SignedInfo>
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315" />
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<Reference URI="#Body">
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<DigestValue>4mt5wluUTu5tpR2d5UemVSLvqTs=</DigestValue>
</Reference>
</SignedInfo>
<SignatureValue>UZ7HzfE3GxIY9hg...</SignatureValue>
<KeyInfo>
<X509Data>
<X509Certificate>MIIEkTCCA3mgAwIBAgIQCu...</X509Certificate>
</X509Data>
<KeyValue>
<RSAKeyValue>
<Modulus>0C3e9HDx5Yq6FLUxIgjJ...</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
</KeyValue>
</KeyInfo>
</Signature>
</soapsec:Signature>
</s:Header>
<s:Body soapsec:id="Body">
.... SOAP Body Here ...
</s:Body>
</s:Envelope>
a oto kod mam w BeforeSendRequest do utworzenia podpisu i modyfikowania wiadomości odpowiednio:
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
XmlDocument doc = new XmlDocument();
doc.PreserveWhitespace = true;
doc.LoadXml(request.ToString());
// Add the required namespaces to the SOAP Envelope element, if I don't do this, the web service I'm calling returns an error
string soapSecNS = "http://schemas.xmlsoap.org/soap/security/2000-12";
string soapEnvNS = "http://www.w3.org/2003/05/soap-envelope";
//Get the header element, so that we can add the digital signature to it
XmlNode headerNode = doc.GetElementsByTagName("Header", soapEnvNS)[0];
// Set the ID attribute on the body element, so that we can reference it later
XmlNode bodyNode = doc.GetElementsByTagName("Body", soapEnvNS)[0];
((XmlElement)bodyNode).RemoveAllAttributes();
((XmlElement)bodyNode).SetAttribute("id", soapSecNS, "Body");
XmlWriterSettings settings2 = new XmlWriterSettings();
settings2.Encoding = new System.Text.UTF8Encoding(false);
// Load the certificate we want to use for signing
SignedXmlWithId signedXml = new SignedXmlWithId(doc);
X509Certificate2 cert = new X509Certificate2("C:\\myCertificate.pfx", "myPassword");
signedXml.SigningKey = cert.PrivateKey;
//Populate the KeyInfo element correctly, with the public cert and public key
Signature sigElement = signedXml.Signature;
KeyInfoX509Data x509Data = new KeyInfoX509Data(cert);
sigElement.KeyInfo.AddClause(x509Data);
RSAKeyValue rsaKeyValue = new RSAKeyValue((RSA)cert.PublicKey.Key);
sigElement.KeyInfo.AddClause(rsaKeyValue);
// Create a reference to be signed, only sign the body of the SOAP request, which we have given an
// ID attribute to, in order to reference it correctly here
Reference reference = new Reference();
reference.Uri = soapSecNS + "#Body";
// Add the reference to the SignedXml object.
signedXml.AddReference(reference);
// Compute the signature.
signedXml.ComputeSignature();
// Get the XML representation of the signature and save
// it to an XmlElement object.
XmlElement xmlDigitalSignature = signedXml.GetXml();
XmlElement soapSignature = doc.CreateElement("Signature", soapSecNS);
soapSignature.Prefix = "soapsec";
soapSignature.AppendChild(xmlDigitalSignature);
headerNode.AppendChild(soapSignature);
// Make sure the byte order mark doesn't get written out
XmlDictionaryReaderQuotas quotas = new XmlDictionaryReaderQuotas();
Encoding encoderWithoutBOM = new System.Text.UTF8Encoding(false);
System.IO.MemoryStream ms = new System.IO.MemoryStream(encoderWithoutBOM.GetBytes(doc.InnerXml));
XmlDictionaryReader xdr = XmlDictionaryReader.CreateTextReader(ms, encoderWithoutBOM, quotas, null);
//Create the new message, that has the digital signature in the header
Message newMessage = Message.CreateMessage(xdr, System.Int32.MaxValue, request.Version);
request = newMessage;
return null;
}
Czy ktoś wie, w jaki sposób ustawić referencyjny identyfikator URI na #Body, ale także mieć prawidłowy podpis XML?
Czy mogę zapytać, dlaczego generowanie podpisu ręcznie, zamiast korzystać z funkcji zabezpieczeń WCF do generowania go dla Ciebie? Czy znalazłeś coś, co nie pozwoli ci używać zabezpieczeń WCF? Btw. masz WSDL z WS-Policy lub prawidłowe żądanie usługi od jakiegoś istniejącego klienta? Są to zazwyczaj niezbędne artefakty, aby zbudować działającego klienta. –
Niestety usługa internetowa nie ma WSDL. Próbowałem użyć zabezpieczeń WCF pierwszy, aby to osiągnąć, ale miałem problem, który opisuję [tutaj] (http://stackoverflow.com/questions/10167814/wcf-the-service-certificate-is-not-provided-for- target-error-for-wcf-client). Sugerowane rozwiązania nie zadziałały, więc zacząłem próbować innej taktyki, w której teraz jestem. Poprosiłem tych, którzy obsługują usługę, o przesłanie mi ważnej prośby, ale jeszcze jej nie mam. Usługa, z którą rozmawiam, nie jest WCF, więc myślę, że utrudnianie korzystania z WCF OOTB. – Cristy
Mam pliki XSD dla usługi, ale użyłem XSD.exe do tworzenia z nich klas C#, a na moim interfejsie serwisowym ustawiłem flagę XmlSerializerFormat, aby umożliwić mi korzystanie z wygenerowanych klas. – Cristy