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

2023-12-10

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

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

任何帮助将不胜感激。

EDIT:以下是我们现在发送的状态请求 Soap 信封以及手动创建的整个 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>

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

EDIT:经验证,由于 WCF 的消息传递架构,这一切都不起作用。 IRS 结构需要修改 HTTP 标头才能使 MTOM 正常工作,而在 XML 序列化发生之后就无法在 WCF 中进行修改。您必须手动构建 XML 并通过 HttpClient 发送它,并自行进行 GZip 和 MTOM 编码。关于这些坏消息我很遗憾 :(

WCF gzip: Take the sample here and integrate the classes and client config with your app. https://msdn.microsoft.com/en-us/library/ms751458.aspx

You'll have to tweak the content type to be "text/xml" instead of "application/x-gzip".

This still will be rejected by the IRS because this doesn't set the "Content-Encoding" header. You can set the content encoding this way:

using (new OperationContextScope(transmitterClient.InnerChannel))
{
// Add a HTTP Header to an outgoing request
HttpRequestMessageProperty requestMessage = new HttpRequestMessageProperty();
requestMessage.Headers["Content-Encoding"] = "gzip";
OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestMessage;
return port.BulkRequestTransmitter(request);
}


Thanks to this blog post for that: http://blogs.msdn.com/b/wsdevsol/archive/2014/02/07/adding-custom-messageheader-and-http-header-to-a-wcf-method-call.aspx

Additionally, IRS's response is NOT gzipped, so you need to modify the class to not try to decompress the response.

Additionally, additionally, the innerMessageEncoding messageVersion default is NOT compatible with the IRS. You have to modify the ApplyConfiguration method of the GZipMessageEncodingElement to instantiate the TextMessageEncodingBindingElement to the MessageVersion.Soap11WSAddressing10 enum with Encoding.UTF8

MTOM My bindings look like this:

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

And then a custom behavior aiming at my cert.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐