C#/IRS ACA - отправка запроса веб-службы с вложением MTOM и кодированием GZip с использованием WCF 4.5
Мы пытаемся отправить данные в IRS через открытую веб-службу для передачи данных ACA, и мы не можем заставить работать подход WSE 3.0 из-за порядка элементов Timestamp и Signature в заголовке безопасности. Проверка XSD на стороне IRS показывает ошибку, когда элемент TimeStamp появляется перед элементом Signature. Когда мы использовали утверждение политики для создания заголовка безопасности вручную с правильным порядком элементов Signature и Timestamp, веб-служба IRS выдает ошибку "Недопустимый заголовок безопасности WS".
Может ли кто-нибудь иметь такую же проблему, пожалуйста, сообщите нам, что может быть возможным исправить. Решением является использование WCF 4.5 вместо WSE 3.0. Можете ли вы предоставить рабочий пример, который обрабатывает как вложение MTOM, так и кодирование GZip с использованием WCF 4.5
Любая помощь будет принята с благодарностью.
РЕДАКТИРОВАТЬ: Ниже приведен конверт мыла с запросом статуса, который мы отправляем сейчас с полным XML-кодом, созданным вручную. Это все еще показывает TPE - 1122 Ошибка заголовка безопасности. Есть ли ошибки с этим запросом?
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:oas1="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:us:gov:treasury:irs:msg:irstransmitterstatusrequest" xmlns:urn1="urn:us:gov:treasury:irs:ext:aca:air:7.0" xmlns:urn2="urn:us:gov:treasury:irs:common" xmlns:urn3="urn:us:gov:treasury:irs:msg:acasecurityheader">
<soapenv:Header xmlns:wsa="http://www.w3.org/2005/08/addressing">
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<ds:Signature Id="SIG-E68EBBF1696C5DD4AA143353323390579" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments" />
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<ds:Reference URI="#TS-82E7E6716E615C14D6144736030985954">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<InclusiveNamespaces PrefixList="wsse wsa oas1 soapenv urn urn1 urn2 urn3" xmlns="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>[Digest_Value_Replaced]</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#id-82E7E6716E615C14D6144736030986559">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<InclusiveNamespaces PrefixList="oas1 soapenv urn1 urn2 urn3" xmlns="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>[Digest_Value_Replaced]</ds:DigestValue>
</ds:Reference>
<ds:Reference URI="#id-82E7E6716E615C14D6144736030986558">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
<InclusiveNamespaces PrefixList="wsa oas1 soapenv urn1 urn2 urn3" xmlns="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:Transform>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>[Digest_Value_Replaced]</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue>[Signature_Value_Replaced]</ds:SignatureValue>
<ds:KeyInfo Id="KI-82E7E6716E615C14D6144736030986456">
<wsse:SecurityTokenReference wsu:Id="STR-82E7E6716E615C14D6144736030986457" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:KeyIdentifier EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">[Cert_Value_Replaced]</wsse:KeyIdentifier>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
<wsu:Timestamp wsu:Id="TS-82E7E6716E615C14D6144736030985954">
<wsu:Created>2016-03-23T09:53:23:55Z</wsu:Created>
<wsu:Expires>2016-03-23T10:03:23:55Z</wsu:Expires>
</wsu:Timestamp>
</wsse:Security>
<urn:ACABusinessHeader wsu:Id="id-82E7E6716E615C14D6144736030986558" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<urn1:UniqueTransmissionId>uuid:SYS12:tcc_cd::T</urn1:UniqueTransmissionId>
<urn2:Timestamp>2016-03-23T09:53:23:55Z</urn2:Timestamp>
</urn:ACABusinessHeader>
<urn3:ACASecurityHeader/>
<wsa:Action>RequestSubmissionStatusDetail</wsa:Action>
</soapenv:Header>
<soapenv:Body>
<urn:ACABulkRequestTransmitterStatusDetailRequest version="1.0" wsu:Id="id-82E7E6716E615C14D6144736030986559" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<urn1:ACABulkReqTrnsmtStsReqGrpDtl>
<urn2:ReceiptId>[ReceiptId_Value_Replaced]</urn2:ReceiptId>
</urn1:ACABulkReqTrnsmtStsReqGrpDtl>
</urn:ACABulkRequestTransmitterStatusDetailRequest>
</soapenv:Body>
</soapenv:Envelope>
РЕДАКТИРОВАТЬ 2: Вот метод, который я использую, чтобы подписать конверт и создать элемент подписи. ВСЕ ЕЩЕ ОШИБКА ЖАТКИ БЕЗОПАСНОСТИ...:(
public static string getSignedXML(XmlDocument xmlDoc, RSACryptoServiceProvider key, string signatureNamespacePrefix,
string sTimeStampId, string sManifestId, string sBusHeaderId)
{
xmlDoc.PreserveWhitespace = false; //Ignore the whitespace in XML
SignedXml signedXml = new CustomIdSignedXml(xmlDoc); //If Id attribute needs to have a prefix. This is not needed as per latest Reference Guide Info.
//SignedXml signedXml = new SignedXml(xmlDoc);
// Add the key to the SignedXml document.
signedXml.SigningKey = key;
signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;
signedXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NWithCommentsTransformUrl;
signedXml.SignedInfo.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;
signedXml.Signature.Id = "SIG-E68EBBF1696C5DD4AA143353323390579";
//------------------------------------------------------------------------
//START OF: Adding Manifest, BusinessHeader and TimeStamp References
//------------------------------------------------------------------------
//Adding Timestamp Reference
XmlDsigExcC14NTransform timeStampTransform = new XmlDsigExcC14NTransform();
timeStampTransform.InclusiveNamespacesPrefixList = "wsse wsa oas1 soapenv urn urn1 urn2 urn3";
Reference reference = new Reference("#" + sTimeStampId);
reference.AddTransform(timeStampTransform);
// Add the reference to the SignedXml object.
signedXml.AddReference(reference);
//Adding Business Header Reference
XmlDsigExcC14NTransform busHeaderTransform = new XmlDsigExcC14NTransform();
busHeaderTransform.InclusiveNamespacesPrefixList = "wsa oas1 soapenv urn1 urn2 urn3";
reference = new Reference("#" + sBusHeaderId);
reference.AddTransform(busHeaderTransform);
// Add the reference to the SignedXml object.
signedXml.AddReference(reference);
//Adding Manifest Request Dtl Reference
XmlDsigExcC14NTransform manifestTransform = new XmlDsigExcC14NTransform();
manifestTransform.InclusiveNamespacesPrefixList = "oas1 soapenv urn1 urn2 urn3";
reference = new Reference("#" + sManifestId);
reference.AddTransform(manifestTransform);
// Add the reference to the SignedXml object.
signedXml.AddReference(reference);
//------------------------------------------------------------------------
//END OF: Adding Manifest, BusinessHeader and TimeStamp References
//------------------------------------------------------------------------
signedXml.ComputeSignature();
XmlElement xmlSignature = signedXml.GetXml(); //Get the singed XML block
if (!string.IsNullOrEmpty(signatureNamespacePrefix))
{
//Here we set the namespace prefix on the signature element and all child elements to "ds", invalidating the signature.
AssignNameSpacePrefixToElementTree(xmlSignature, "ds");
//So let's recompute the SignatureValue based on our new SignatureInfo...
//For XPath
XmlNamespaceManager namespaceManager = new XmlNamespaceManager(xmlDoc.NameTable);
namespaceManager.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#"); //this prefix is arbitrary and used only for XPath
XmlElement xmlSignedInfo = xmlSignature.SelectSingleNode("ds:SignedInfo", namespaceManager) as XmlElement;
//Canonicalize the SignedInfo element
XmlDsigC14NTransform transform = new XmlDsigC14NTransform();
XmlDocument signedInfoDoc = new XmlDocument();
signedInfoDoc.LoadXml(xmlSignedInfo.OuterXml);
transform.LoadInput(signedInfoDoc);
//Compute the new SignatureValue
string signatureValue = Convert.ToBase64String(key.SignData(transform.GetOutput() as MemoryStream, new SHA1CryptoServiceProvider()));
//Set it in the xml
XmlElement xmlSignatureValue = xmlSignature.SelectSingleNode("ds:SignatureValue", namespaceManager) as XmlElement;
xmlSignatureValue.InnerText = signatureValue;
}
//xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlSignature, true));
//----------------------------------------------------------------------------------
//START OF: Add Key Info Element also to the XML after SignatureValue Node.
//----------------------------------------------------------------------------------
X509Certificate2 mycert = new X509Certificate2(<Cert_Path>, <Cert_Password>);
//bulkReqTransmitService.ClientCertificates.Add(mycert);
var exported = mycert.Export(X509ContentType.Cert, <Cert_Password>);
var base64 = Convert.ToBase64String(exported);
StringBuilder sbKeyInfo = new StringBuilder();
string dsStartTagPrefix = "";
string dsEndTagPrefix = "/";
if (!string.IsNullOrEmpty(signatureNamespacePrefix))
{
dsStartTagPrefix = "ds:";
dsEndTagPrefix = "/ds:";
}
sbKeyInfo.Append("<root xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">");
sbKeyInfo.Append("<" + dsStartTagPrefix + "KeyInfo Id=\"KI-82E7E6716E615C14D6144736030986456\">");
sbKeyInfo.Append("<wsse:SecurityTokenReference wsu:Id=\"STR-82E7E6716E615C14D6144736030986457\">");
sbKeyInfo.Append("<wsse:KeyIdentifier EncodingType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary\" ValueType=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3\">" + base64.ToString());
sbKeyInfo.Append("</wsse:KeyIdentifier>");
sbKeyInfo.Append("</wsse:SecurityTokenReference>");
sbKeyInfo.Append("<" + dsEndTagPrefix + "KeyInfo>");
sbKeyInfo.Append("</root>");
XmlDocument tempDoc = new XmlDocument();
tempDoc.LoadXml(sbKeyInfo.ToString());
XmlNode oNode = tempDoc.DocumentElement;
//necessary for crossing XmlDocument contexts
XmlNode importNode = xmlSignature.OwnerDocument.ImportNode(oNode.FirstChild, true);
xmlSignature.AppendChild(importNode);
//----------------------------------------------------------------------------------
//END OF: Add Key Info Element also to the XML after SignatureValue Node.
//----------------------------------------------------------------------------------
return xmlSignature.OuterXml;
}
public class CustomIdSignedXml : SignedXml
{
public CustomIdSignedXml(XmlDocument xml) : base(xml)
{
}
public CustomIdSignedXml(XmlElement xmlElement)
: base(xmlElement)
{
}
public override XmlElement GetIdElement(XmlDocument doc, string id)
{
// check to see if it's a standard ID reference
XmlElement idElem = base.GetIdElement(doc, id);
if (idElem == null)
{
XmlNamespaceManager nsManager = new XmlNamespaceManager(doc.NameTable);
nsManager.AddNamespace("wsu", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd");
//idElem = doc.SelectSingleNode("//*[@p5:Id=\"" + id + "\"]", nsManager) as XmlElement;
string xml = doc.SelectSingleNode("//*[@wsu:Id=\"" + id + "\"]", nsManager).OuterXml;
XmlDocument tempDoc = new XmlDocument();
tempDoc.LoadXml(xml);
XmlElement xEle = tempDoc.DocumentElement;
idElem = xEle;
}
return idElem;
}
}
2 ответа
РЕДАКТИРОВАТЬ: Проверено, ничего из этого не будет работать из-за архитектуры обмена сообщениями WCF. Структура IRS требует модификации заголовков HTTP для MTOM для правильной работы, которую нельзя изменить в WCF после того момента, когда происходит сериализация XML. Вам нужно будет создать свой XML вручную и отправить его через HttpClient и самостоятельно выполнить кодирование GZip и MTOM. Извините за плохие новости:(
WCF gzip: возьмите образец здесь и интегрируйте классы и конфигурацию клиента с вашим приложением. https://msdn.microsoft.com/en-us/library/ms751458.aspx
Вам придется настроить тип контента так, чтобы он был "text/xml" вместо "application/x-gzip".
Это все еще будет отклонено IRS, потому что это не устанавливает заголовок "Content-Encoding". Вы можете установить кодировку контента следующим образом:
{
// Добавить заголовок HTTP к исходящему запросу
HttpRequestMessageProperty requestMessage = new HttpRequestMessageProperty ();
requestMessage.Headers ["Content-Encoding"] = "gzip";
OperationContext.Current.OutgoingMessageProperties [HttpRequestMessageProperty.Name] = requestMessage;
возврат port.BulkRequestTransmitter(запрос);
}
Спасибо за это сообщение в блоге: http://blogs.msdn.com/b/wsdevsol/archive/2014/02/07/adding-custom-messageheader-and-http-header-to-a-wcf-method-call.aspx
Кроме того, ответ IRS НЕ разархивирован, поэтому вам нужно изменить класс, чтобы не пытаться распаковать ответ.
Кроме того, дополнительно, defaultMessageEncoding messageVersion по умолчанию НЕ совместимо с IRS. Необходимо изменить метод ApplyConfiguration в GZipMessageEncodingElement, чтобы создать экземпляр TextMessageEncodingBindingElement для перечисления MessageVersion.Soap11WSAddressing10 с Encoding.UTF8
MTOM Мои привязки выглядят так:
<bindings>
<customBinding>
<binding name="BulkRequestTransmitterBinding">
<gzipMessageEncoding innerMessageEncoding="textMessageEncoding" />
<security enableUnsecuredResponse="true" authenticationMode="MutualCertificate" messageSecurityVersion="WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10"/>
<httpsTransport />
</binding>
</customBinding>
</bindings>
А потом нестандартное поведение, направленное на мой сертификат.
У меня пока нет репутации, чтобы фактически оставлять комментарии к вашим сообщениям>:(
Вот пара дополнительных вопросов для вас относительно процесса, который вы используете.
- Используете ли вы классы WSDL Service Reference/Proxy для выполнения ваших звонков в IRS через канал ISS-A2A?
- После реализации трех файлов классов из примеров я получаю следующую ошибку. Вы видите что-то необычное, что я делаю неправильно?
Дополнительная информация: Тип '[Project].GZipEncoder.GzipMessageEncodingElement, GZipEncoder, Version=1.0.0.0, Culture= нейтральный, PublicKeyToken=null', зарегистрированный для расширения 'gzipMessageEncoding', не может быть загружен.
<gzipMessageEncoding>
элемент в моем <customBinding>
дает мне предупреждение, которое, я думаю, связано с вышеуказанной ошибкой.
app.config
<system.serviceModel>
<extensions>
<bindingElementExtensions>
<add name="gzipMessageEncoding" type="[ProjectName].GZipEncoder.GzipMessageEncodingElement, GZipEncoder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</bindingElementExtensions>
</extensions>
<client>
<endpoint />
<metadata>
<policyImporters>
<extension type="[ProjectName].GZipEncoder.GZipMessageEncodingBindingElementImporter, GZipEncoder, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</policyImporters>
</metadata>
</client>
<bindings>
<customBinding>
<binding name="BulkRequestTransmitterBinding">
<gzipMessageEncoding innerMessageEncoding="textMessageEncoding" />
<httpsTransport />
</binding>
</customBinding>
</bindings>
</system.serviceModel>