【问题标题】:IRS Soap Fault - Invalid WS Security HeaderIRS Soap 故障 - 无效的 WS 安全标头
【发布时间】:2016-04-28 19:30:11
【问题描述】:

我正在尝试向 IRS 发送 Soap 请求,但遇到了与该组中其他人一样的错误 - “无效的 WS 安全标头”。有人可以用肥皂请求样本指导我吗?另一个问题是 - 作为注册过程的一部分,我们向 IRS 网站提交了 X509 证书(公钥),该网站将用于验证/解密您的消息摘要。您为此过程上传了哪个证书文件?我们真的被这个错误困扰了好几天了。感谢您对此的任何帮助。我已经看到关于这个主题的 2 个问题,但没有任何帮助答案。

【问题讨论】:

    标签: web-services wss4j irs


    【解决方案1】:

    我假设这是针对 ACA Air IRS 提交的。我们将 .cer 文件上传到 IRS 站点,您可以在该站点将您的 TCC(例如 BBBBB 格式)与您上传的 .cer 相关联。我们使用的堆栈是:Oracle 的 JDK 8、WSS4J v2.1.4 和 CXF v3.1.4。以下是我们用于签署 IRS 希望签署的参考元素的示例 Java 代码:

     public static SOAPMessage signSoapMessage(SOAPMessage message,
                                              String keystorePassword, String irsPrivateKeyPassword, Class<?> clazz) throws WSSecurityException {
    
        //TODO remove below hard coded
        final String _irsPrivateKeyPassword = "yourprivatekeypasswordyougotfromCA";
        final String _keystorePassword = "yourpasswordtoyourJKS";
        keystorePassword = _keystorePassword;
        irsPrivateKeyPassword = _irsPrivateKeyPassword;
    
        PrivateKeyEntry privateKeyEntry = getPrivateKeyEntry(keystorePassword,
                irsPrivateKeyPassword);
    
        PrivateKey signingKey = privateKeyEntry.getPrivateKey();
        X509Certificate signingCert = (X509Certificate) privateKeyEntry
                .getCertificate();
    
        //TODO add alias to database
        final String alias = "thealiasforthiscertandprivatekey";
        final int signatureValidityTime = 3600; // 1hour in seconds
    
        WSSConfig config = WSSConfig.getNewInstance();
        //config.setWsiBSPCompliant(true);
    
        WsuIdAllocator idAllocator = new WsuIdAllocator() {
    
            @Override
            public String createSecureId(String prefix, Object o) {
                //e.g. <ds:KeyInfo Id="KI-9F6A3A6B473244859D59710683FABFE1">
                if(prefix.equals("KI-"))
                    return "KI-" + UUID.randomUUID().toString().replace("-", "").toUpperCase();
                //e.g. <wsse:SecurityTokenReference wsu:Id="STR-E6C0BA1EC73A4AB3BECFEBF6075EF175">
                else if (prefix.equals("STR-"))
                    return "STR-" + UUID.randomUUID().toString().replace("-", "").toUpperCase();
                //TODO why is there a condition where prefix.equals("X509") and o.toString() is the public cert?
                else
                    return null;
            }
    
            //e.g. <ds:Signature Id="SIG-9850525DA06CE28ED91448475206411147"
            @Override
            public String createId(String prefix, Object o) {
                return "SIG-" + UUID.randomUUID().toString().replace("-", "").toUpperCase();
            }
    
        };      
        config.setIdAllocator(idAllocator );
    
        //WSSecSignature wsSecSignature = new WSSecSignature(config);
        WSSecSignature wsSecSignature = new WSSecSignature();  
    
        wsSecSignature.setX509Certificate(signingCert);
        wsSecSignature.setUserInfo(alias, new String(keystorePassword.toCharArray()));
        wsSecSignature.setUseSingleCertificate(true);
        wsSecSignature.setKeyIdentifierType(WSConstants.X509_KEY_IDENTIFIER);
        //wsSecSignature.setKeyIdentifierType(WSConstants.SKI_KEY_IDENTIFIER);
        wsSecSignature.setDigestAlgo(WSConstants.SHA1);
        wsSecSignature.setSignatureAlgorithm(WSConstants.RSA_SHA1);
        wsSecSignature.setSigCanonicalization(WSConstants.C14N_EXCL_WITH_COMMENTS);
    
        try {
            Document document = toDocument(message);
            WSSecHeader secHeader = new WSSecHeader(document);
            //secHeader.setMustUnderstand(true);
            secHeader.insertSecurityHeader();
    
            WSSecTimestamp timestamp = new WSSecTimestamp();            
            timestamp.setTimeToLive(signatureValidityTime);
            document = timestamp.build(document, secHeader);
    
            List<WSEncryptionPart> wsEncryptionParts = new ArrayList<WSEncryptionPart>();
    
            //Very important, ordering of the parts is critical: refer to page 34 of the guide
            //for ACAGetTransmitterBulkRequestService, it is Timestamp, ACATransmitterManifestReqDtl, ACABusinessHeader
            if(clazz.equals(ACATransmitterManifestReqDtl.class)){
                WSEncryptionPart timestampPart = new WSEncryptionPart("Timestamp",
                        WSConstants.WSU_NS, "");
    
                //This is very important, Timestamp needs to be fist
                wsEncryptionParts.add(timestampPart);            
    
                WSEncryptionPart aCATransmitterManifestReqDtlPart = new WSEncryptionPart(
                    "ACATransmitterManifestReqDtl",
                    "urn:us:gov:treasury:irs:ext:aca:air:7.0", "");
                wsEncryptionParts.add(aCATransmitterManifestReqDtlPart);
    
                WSEncryptionPart aCABusinessHeaderPart = new WSEncryptionPart(
                        "ACABusinessHeader",
                        "urn:us:gov:treasury:irs:msg:acabusinessheader", "");            
                wsEncryptionParts.add(aCABusinessHeaderPart);
            }
            //for ACAGetTransmitterBulkRequestStatus, it is Timestamp, ACABusinessHeader, ACABulkRequestTransmitterStatusDetailRequest
            else if(clazz.equals(ACABulkRequestTransmitterStatusDetailRequest.class)){
                WSEncryptionPart timestampPart = new WSEncryptionPart("Timestamp",
                        WSConstants.WSU_NS, "");
    
                //This is very important, Timestamp needs to be fist
                wsEncryptionParts.add(timestampPart);            
    
                WSEncryptionPart aCABusinessHeaderPart = new WSEncryptionPart(
                        "ACABusinessHeader",
                        "urn:us:gov:treasury:irs:msg:acabusinessheader", "");            
                wsEncryptionParts.add(aCABusinessHeaderPart);
    
                WSEncryptionPart aCABulkRequestTransmitterStatusDetailRequestPart = new WSEncryptionPart(
                        "ACABulkRequestTransmitterStatusDetailRequest",
                        "urn:us:gov:treasury:irs:msg:irstransmitterstatusrequest", "");
                    wsEncryptionParts.add(aCABulkRequestTransmitterStatusDetailRequestPart);
            }
    
            wsSecSignature.getParts().addAll(wsEncryptionParts);
    
            Properties properties = new Properties();
            properties.setProperty("org.apache.ws.security.crypto.provider",
                    "org.apache.ws.security.components.crypto.Merlin");
            Crypto crypto = CryptoFactory.getInstance(properties);
            KeyStore keystore = KeyStore.getInstance("JKS");
    
            java.io.FileInputStream fis = null;
            try {
                fis = new java.io.FileInputStream(System.getProperty("java.home") + "//lib//security//meckeystore.jks");
                if(fis != null) {
                    keystore.load(fis, keystorePassword.toCharArray());
                } else {
                    //TODO: replace with custom MEC exception
                    throw new Exception("Unable to read keystore file.");
                }
    
            } finally {
                if (fis != null) {
                    fis.close();
                }
            }
    
            keystore.setKeyEntry(alias, signingKey, keystorePassword.toCharArray(),
                    new Certificate[]{signingCert});
            ((Merlin) crypto).setKeyStore(keystore);
            crypto.loadCertificate(new ByteArrayInputStream(signingCert.getEncoded()));
    
            document = wsSecSignature.build(document, crypto, secHeader);
    
            updateSOAPMessage(document, message);
    
    
        } catch (Exception e) {
            // throw new
            // WSSecurityException(WSSecurityException.Reason.SIGNING_ISSUE, e);
            e.printStackTrace();
        }
    
        return message;
    }
    
    /**
     * Changes the SOAPMessage to a dom.Document.
     */
    private static Document toDocument(SOAPMessage soapMsg) throws TransformerException,
            SOAPException, IOException {
        Source src = soapMsg.getSOAPPart().getContent();
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();
        DOMResult result = new DOMResult();
        transformer.transform(src, result);
        return (Document) result.getNode();
    }
    
    //https://svn.apache.org/repos/asf/webservices/wss4j/branches/WSS4J_1_1_0_FINAL/test/wssec/SOAPUtil.java
    private static SOAPMessage updateSOAPMessage(Document doc,
                                                 SOAPMessage message)
            throws Exception {
        DOMSource domSource = new DOMSource(doc);
        message.getSOAPPart().setContent(domSource);
        return message;
    }
    

    这是示例 SOAP 请求

    <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:us:gov:treasury:irs:ext:aca:air:7.0" xmlns:urn1="urn:us:gov:treasury:irs:common">
       <SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
      <wsse:Security SOAP-ENV:mustUnderstand="1" 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-d62ad452-5219-4baf-9708-3ae1d2cf7e92" 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-6450a75d-45e4-463b-a1e8-2d3ae3b4c57c">
                  <ds:Transforms>
                     <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                        <InclusiveNamespaces PrefixList="wsse SOAP-ENV soap urn urn1" 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>ojqiqHiXxPWIaEumCOO3bKJZ73A=</ds:DigestValue>
               </ds:Reference>
               <ds:Reference URI="#id-0EB7188D138D494EA44AC09FE03F6BEE">
                  <ds:Transforms>
                     <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                        <InclusiveNamespaces PrefixList="SOAP-ENV soap urn urn1" 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>cm3KGHFWHyJcBU9MEQzw6Ru04z0=</ds:DigestValue>
               </ds:Reference>
               <ds:Reference URI="#id-1183235E8ED44DE99B069411CD4837DC">
                  <ds:Transforms>
                     <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
                        <InclusiveNamespaces PrefixList="SOAP-ENV soap urn urn1" 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>6nM3ONVPyHtiupcznWiixpNG82k=</ds:DigestValue>
               </ds:Reference>
            </ds:SignedInfo>
            <ds:SignatureValue>removed==</ds:SignatureValue>
            <ds:KeyInfo Id="KI-e6a6c681-ccf7-49ab-a37f-dac69c52d32a">
               <wsse:SecurityTokenReference wsu:Id="STR-c1b4d47e-fda6-49b0-a58a-7df24ab43e13">
                  <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">removed</wsse:KeyIdentifier>
               </wsse:SecurityTokenReference>
            </ds:KeyInfo>
         </ds:Signature>
         <wsu:Timestamp wsu:Id="TS-6450a75d-45e4-463b-a1e8-2d3ae3b4c57c">
            <wsu:Created>2016-01-27T23:59:36.352Z</wsu:Created>
            <wsu:Expires>2016-01-28T00:59:36.352Z</wsu:Expires>
         </wsu:Timestamp>
      </wsse:Security>
      <ACATransmitterManifestReqDtl ns3:Id="id-0EB7188D138D494EA44AC09FE03F6BEE" xmlns="urn:us:gov:treasury:irs:ext:aca:air:7.0" xmlns:ns2="urn:us:gov:treasury:irs:common" xmlns:ns3="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
         <PaymentYr>2015</PaymentYr>
         <PriorYearDataInd>0</PriorYearDataInd>
         <ns2:EIN></ns2:EIN>
         <TransmissionTypeCd>O</TransmissionTypeCd>
         <TestFileCd>T</TestFileCd>
         <TransmitterNameGrp>
            <BusinessNameLine1Txt></BusinessNameLine1Txt>
            <BusinessNameLine2Txt>Health Systems</BusinessNameLine2Txt>
         </TransmitterNameGrp>
         <CompanyInformationGrp>
            <CompanyNm></CompanyNm>
            <MailingAddressGrp>
               <USAddressGrp>
                  <AddressLine1Txt></AddressLine1Txt>
                  <ns2:CityNm>Rockville</ns2:CityNm>
                  <USStateCd>MD</USStateCd>
                  <ns2:USZIPCd></ns2:USZIPCd>
               </USAddressGrp>
            </MailingAddressGrp>
            <ContactNameGrp>
               <PersonFirstNm></PersonFirstNm>
               <PersonMiddleNm>X</PersonMiddleNm>
               <PersonLastNm></PersonLastNm>
            </ContactNameGrp>
            <ContactPhoneNum></ContactPhoneNum>
         </CompanyInformationGrp>
         <VendorInformationGrp>
            <VendorCd>I</VendorCd>
            <ContactNameGrp>
               <PersonFirstNm></PersonFirstNm>
               <PersonMiddleNm></PersonMiddleNm>
               <PersonLastNm></PersonLastNm>
            </ContactNameGrp>
            <ContactPhoneNum></ContactPhoneNum>
         </VendorInformationGrp>
         <TotalPayeeRecordCnt>1000</TotalPayeeRecordCnt>
         <TotalPayerRecordCnt>1</TotalPayerRecordCnt>
         <SoftwareId></SoftwareId>
         <FormTypeCd>1094/1095B</FormTypeCd>
         <ns2:BinaryFormatCd>application/xml</ns2:BinaryFormatCd>
         <ns2:ChecksumAugmentationNum>5bae956d7c6a01c95ce570dd11debe78</ns2:ChecksumAugmentationNum>
         <ns2:AttachmentByteSizeNum>5938</ns2:AttachmentByteSizeNum>
         <DocumentSystemFileNm>1094B_Request_BBBBB_20151019T121002000Z.xml</DocumentSystemFileNm>
      </ACATransmitterManifestReqDtl>
      <urn2:ACABusinessHeader wsu:Id="id-1183235E8ED44DE99B069411CD4837DC" xmlns:urn2="urn:us:gov:treasury:irs:msg:acabusinessheader" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
         <urn:UniqueTransmissionId>d81ead9b-1223-4d28-8d46-f7af58710268:SYS12:BBBBB::T</urn:UniqueTransmissionId>
         <urn1:Timestamp>2016-01-27T23:59:36Z</urn1:Timestamp>
      </urn2:ACABusinessHeader>
      <Action xmlns="http://www.w3.org/2005/08/addressing">RequestSubmissionStatusDetail</Action>
    

    对我们来说真正的关键在于 IRS 文档中的这一点,因为我们使用的是 Apache CXF v2.1.4:

    用于 7bit 内容类型编码和内容类型的 Big Hack

    5.4.2(来自 IRS 文档) 消息附件内容类型 ISS-A2AAIR Web 服务要求发送器使用 SOAP-over-HTTP 消息与 MTOM 来发送 XML 数据文件。 在 MTOM 附件中编码的文件必须是未压缩的原生 XML。中标识的 MTOM 编码二进制对象的内容类型 Manifest 标头必须是“application/xml”。表单数据文件的内容传输编码必须是 7 位。

    在apache-cxf-3.1.4-src/core/src/main/java/org/apache/cxf/attachment/AttachmentSerializer.java里面

    194     private static void writeHeaders(String contentType, String attachmentId,
    195                                      Map<String, List<String>> headers, Writer writer) throws IOException {
    196 //        writer.write("\r\nContent-Type: ");
    197 //        writer.write(contentType);
    198 writer.write("\r\nContent-Type: application/xml");
    199 //        writer.write("\r\nContent-Transfer-Encoding: binary\r\n");
    200 writer.write("\r\nContent-Transfer-Encoding: 7bit\r\n");
    

    【讨论】:

    • 是的,这是为 IRS 提交的。感谢您提及使用的堆栈,非常有帮助。您只有一个 .cer 文件吗?如果有,它的名字是什么?我得到了 3 个文件——服务器、root 和 subca1。您是否能够通过 Code & Soap UI 工具成功向 IRS 发送肥皂请求?目前,我正在尝试通过肥皂 UI 发送它,但没有成功。我正在通过 Soap UI 设置生成安全标头。你能给我一份肥皂样品请求吗?我有很多问题要问你,你能给我你的电子邮件/电话联系方式吗@shathaj@gmail.com
    • 我已将示例 SoapUI 请求发送到您的电子邮件。
    • 示例 SOAP 请求现在是我回答的一部分。
    • 非常感谢!我可以通过您的示例请求成功向 IRS 发送请求。
    • 为什么您的标头“RequestSubmissionStatusDetail”中的操作是 ACATransmitterManifestReqDtl。事实上,您的 3 个 DigestValue HREF 之一指向它,而不是 ACABulkRequestTransmitterStatusDetailRequest 元素,如其文档所述。他们的文档是否严重不正确,我们应该按照您的演示进行操作。或者这只是你将这个样本转录到 Stack Overflow 上的产物?
    【解决方案2】:

    Prabhat,我认为 MTOM 和 SwA 不能齐头并进。您可以使用其中任何一种。启用 MTOM 后,您将无法使用附件 API (SwA)。

    【讨论】:

      猜你喜欢
      • 2016-04-13
      • 2016-06-04
      • 1970-01-01
      • 2016-09-23
      • 1970-01-01
      • 2015-11-05
      • 1970-01-01
      • 2014-02-11
      • 2016-03-24
      相关资源
      最近更新 更多