C#/IRS ACA - 使用 WCF 4.5 发送带有 MTOM 附件和 GZip 编码的 Web 服务请求

标签 c# web-services gzip mtom irs

我们正在尝试通过公开的 Web 服务向 IRS 发送数据以进行 ACA 数据传输,但由于安全 header 中时间戳和签名元素的顺序,我们无法使 WSE 3.0 方法发挥作用。当 TimeStamp 元素出现在 Signature 元素之前时,IRS 端的 XSD 验证显示错误。当我们使用策略断言手动生成具有正确顺序的签名和时间戳元素的安全 header 时,IRS Web 服务显示“无效的 WS 安全 header ”错误。

谁有同样的问题,请告诉我们可能的解决方法。使用 WCF 4.5 而不是 WSE 3.0 是解决方案,您能否提供一个使用 WCF 4.5 处理 MTOM 附件和 GZip 编码的工作示例

如有任何帮助,我们将不胜感激。

编辑: 以下是我们现在发送的状态请求 Soap 信封,其中包含手动创建的整个 XML。它仍然显示 TPE - 1122 Invalid Security Header Error。这个请求有没有错误?

<?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::这是我用来签署信封和创建签名元素的方法。仍然收到安全 header 错误... :(

 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;
        }
    }

最佳答案

编辑:已验证由于 WCF 的消息传递架构,这些都不起作用。 IRS 结构需要修改 HTTP header 才能使 MTOM 正常工作,这在 XML 序列化发生后无法在 WCF 中修改。您必须手动构建 XML 并通过 HttpClient 发送它,然后自己进行 GZip 和 MTOM 编码。对不起坏消息:(

WCF gzip: 在此处获取示例并将类和客户端配置与您的应用程序集成。 https://msdn.microsoft.com/en-us/library/ms751458.aspx

您必须将内容类型调整为“text/xml”而不是“application/x-gzip”。

这仍然会被 IRS 拒绝,因为它没有设置“Content-Encoding” header 。您可以这样设置内容编码:



<删除> 使用(新的 OperationContextScope(transmitterClient.InnerChannel))
{
//向传出请求添加 HTTP header
HttpRequestMessageProperty requestMessage = new HttpRequestMessageProperty();
requestMessage.Headers["Content-Encoding"] = "gzip";
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestMessage;
返回端口.BulkRequestTransmitter(请求);
}


感谢这篇博文:http://blogs.msdn.com/b/wsdevsol/archive/2014/02/07/adding-custom-messageheader-and-http-header-to-a-wcf-method-call.aspx

此外,IRS 的响应未压缩,因此您需要修改类以不尝试解压缩响应。

此外,innerMessageEncoding messageVersion 默认值与 IRS 不兼容。您必须修改 GZipMessageEncodingElement 的 ApplyConfiguration 方法,以使用 Encoding.UTF8 将 TextMessageEncodingBindingElement 实例化为 MessageVersion.Soap11WSAddressing10 枚举

多线程 我的绑定(bind)看起来像这样:

<bindings>
  <customBinding>
    <binding name="BulkRequestTransmitterBinding">
      <gzipMessageEncoding innerMessageEncoding="textMessageEncoding" />
      <security enableUnsecuredResponse="true" authenticationMode="MutualCertificate" messageSecurityVersion="WSSecurity10WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10"/>
      <httpsTransport />
    </binding>
  </customBinding>
</bindings>  

然后是针对我的证书的自定义行为。

关于C#/IRS ACA - 使用 WCF 4.5 发送带有 MTOM 附件和 GZip 编码的 Web 服务请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35182951/

相关文章:

java - 使用 Java 的 Web 服务自动化

mysql - 在 bash 流中压缩文件时保留文件名

json - 用于在 API 上发布的 Python 3 Gzip json

c# - ASP.NET 中的 JavaScript 脚本

java - 从具有 Web 服务的基本 Java 项目到可部署的 Glassfish 工件?

c# - Visual Studio 2017 安装项目错误 2727

java - 没有端点 URL 的 WSDL

ios - 启用 gzip 的 NSURLCache 和 ETags 不工作

c# - ListBox ItemTemplate 中的按钮未选择项目

c# - 如何建模自引用对象类型?