Web Services 手动签署SOAP消息Java

y0u0uwnf  于 2022-11-15  发布在  Java
关注(0)|答案(4)|浏览(302)

我必须使用java对Soap消息进行签名,但是我不能使用WSS4J、SAAJ、AXIS2或CXF来解决websphere服务器上的类路径问题。
我必须对SOAP调用的正文消息进行签名。
我为soap消息正确地生成了一个包含body内部body数据的XML,如下所示:

<SERVICE_DISPATCHER_REQUEST xmlns="http://inti.notariado.org/XML" xmlns:ns2="http://ancert.notariado.org/XML/CSN"><ns2:SERVICIO_CONSIGNACION_NOTARIAL><ns2:REQUEST><ns2:CABECERA><ns2:ID_COMUNICACION>2147483647</ns2:ID_COMUNICACION><ns2:FECHA>2016-03-22</ns2:FECHA><ns2:HORA>10:55:00</ns2:HORA><ns2:TIPO_OPERACION>TRANSFERENCIA</ns2:TIPO_OPERACION></ns2:CABECERA><ns2:MENSAJE><ns2:TRANSFERENCIA><ns2:CODIGO_SERVICIO>DEUDAS</ns2:CODIGO_SERVICIO><ns2:REFERENCIA>999988887777666655</ns2:REFERENCIA><ns2:FECHA_EMISION>2016-03-24</ns2:FECHA_EMISION><ns2:FECHA_VALOR>2016-03-25</ns2:FECHA_VALOR><ns2:NOTARIO><ns2:CODIGO_ULTIMAS_VOLUNTADES>9900005</ns2:CODIGO_ULTIMAS_VOLUNTADES><ns2:TIP_DOC_IDENTIFICACION>1</ns2:TIP_DOC_IDENTIFICACION><ns2:NUM_DOC_IDENTIFICACION>11711111H</ns2:NUM_DOC_IDENTIFICACION></ns2:NOTARIO><ns2:IMPORTE>1.00</ns2:IMPORTE><ns2:MONEDA>EUR</ns2:MONEDA><ns2:ORDENANTE>JUAN PEREZ SANCHEZ</ns2:ORDENANTE><ns2:CONCEPTO>Pago deuda inmueble Santurze</ns2:CONCEPTO></ns2:TRANSFERENCIA><ns2:TRANSFERENCIA><ns2:CODIGO_SERVICIO>DEUDAS</ns2:CODIGO_SERVICIO><ns2:REFERENCIA>999988887777666655</ns2:REFERENCIA><ns2:FECHA_EMISION>2016-03-24</ns2:FECHA_EMISION><ns2:FECHA_VALOR>2016-03-25</ns2:FECHA_VALOR><ns2:NOTARIO><ns2:CODIGO_ULTIMAS_VOLUNTADES>9900005</ns2:CODIGO_ULTIMAS_VOLUNTADES><ns2:TIP_DOC_IDENTIFICACION>1</ns2:TIP_DOC_IDENTIFICACION><ns2:NUM_DOC_IDENTIFICACION>11711111H</ns2:NUM_DOC_IDENTIFICACION></ns2:NOTARIO><ns2:IMPORTE>2.00</ns2:IMPORTE><ns2:MONEDA>EUR</ns2:MONEDA><ns2:ORDENANTE>JUAN PEREZ SANCHEZ</ns2:ORDENANTE><ns2:CONCEPTO>Pago deuda inmueble Santurze</ns2:CONCEPTO></ns2:TRANSFERENCIA></ns2:MENSAJE></ns2:REQUEST>

最佳视图格式:

<SERVICE_DISPATCHER_REQUEST xmlns="http://inti.notariado.org/XML" xmlns:ns2="http://ancert.notariado.org/XML/CSN">
<ns2:SERVICIO_CONSIGNACION_NOTARIAL>
    <ns2:REQUEST>
        <ns2:CABECERA>
            <ns2:ID_COMUNICACION>2147483647</ns2:ID_COMUNICACION>
            <ns2:FECHA>2016-03-22</ns2:FECHA>
            <ns2:HORA>10:55:00</ns2:HORA>
            <ns2:TIPO_OPERACION>TRANSFERENCIA</ns2:TIPO_OPERACION>
        </ns2:CABECERA>
        <ns2:MENSAJE>
            <ns2:TRANSFERENCIA>
                <ns2:CODIGO_SERVICIO>DEUDAS</ns2:CODIGO_SERVICIO>
                <ns2:REFERENCIA>999988887777666655</ns2:REFERENCIA>
                <ns2:FECHA_EMISION>2016-03-24</ns2:FECHA_EMISION>
                <ns2:FECHA_VALOR>2016-03-25</ns2:FECHA_VALOR>
                <ns2:NOTARIO>
                    <ns2:CODIGO_ULTIMAS_VOLUNTADES>9900005</ns2:CODIGO_ULTIMAS_VOLUNTADES>
                    <ns2:TIP_DOC_IDENTIFICACION>1</ns2:TIP_DOC_IDENTIFICACION>
                    <ns2:NUM_DOC_IDENTIFICACION>11711111H</ns2:NUM_DOC_IDENTIFICACION>
                </ns2:NOTARIO><ns2:IMPORTE>1.00</ns2:IMPORTE>
                <ns2:MONEDA>EUR</ns2:MONEDA>
                <ns2:ORDENANTE>JUAN PEREZ SANCHEZ</ns2:ORDENANTE>
                <ns2:CONCEPTO>Pago deuda inmueble Santurze</ns2:CONCEPTO>
            </ns2:TRANSFERENCIA>
            <ns2:TRANSFERENCIA>
                <ns2:CODIGO_SERVICIO>DEUDAS</ns2:CODIGO_SERVICIO>
                <ns2:REFERENCIA>999988887777666655</ns2:REFERENCIA>
                <ns2:FECHA_EMISION>2016-03-24</ns2:FECHA_EMISION>
                <ns2:FECHA_VALOR>2016-03-25</ns2:FECHA_VALOR>
                <ns2:NOTARIO>
                    <ns2:CODIGO_ULTIMAS_VOLUNTADES>9900005</ns2:CODIGO_ULTIMAS_VOLUNTADES>
                    <ns2:TIP_DOC_IDENTIFICACION>1</ns2:TIP_DOC_IDENTIFICACION>
                    <ns2:NUM_DOC_IDENTIFICACION>11711111H</ns2:NUM_DOC_IDENTIFICACION>
                </ns2:NOTARIO>
                <ns2:IMPORTE>2.00</ns2:IMPORTE>
                <ns2:MONEDA>EUR</ns2:MONEDA>
                <ns2:ORDENANTE>JUAN PEREZ SANCHEZ</ns2:ORDENANTE>
                <ns2:CONCEPTO>Pago deuda inmueble Santurze</ns2:CONCEPTO>
            </ns2:TRANSFERENCIA>
        </ns2:MENSAJE>
    </ns2:REQUEST>
</ns2:SERVICIO_CONSIGNACION_NOTARIAL>

然后,我使用前面的XML(带有主体开始和结束标记)执行哈希值以创建摘要值:

// Change value if there is any problem on websphere
        // wsuId = "\"#MsgBody\"";
        wsuId = "\"#id-" + UUIDGenerator.getUUID() + "\"";
        // Create XML data for body SOAP
        String dataXMLSoap = generateBodySoap(doc);
        String startBodyHash = "<soapenv:Body xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" wsu:Id=" + wsuId+ ">";
        String endBodyHash  = "</soapenv:Body>";
        MessageDigest messageDigestFromBody= MessageDigest.getInstance("SHA-1");            
        String xmlHash = startBodyHash + dataXMLSoap + endBodyHash;
        byte[] hashSoapBody = messageDigestFromBody.digest(xmlHash.getBytes());
        String digestValueFromBody = new BASE64Encoder().encode(hashSoapBody);

XML哈希示例:

<soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" wsu:Id="#id-D1DD0227ECDC46640D147197713960845"><SERVICE_DISPATCHER_REQUEST xmlns="http://inti.notariado.org/XML" xmlns:ns2="http://ancert.notariado.org/XML/CSN"><ns2:SERVICIO_CONSIGNACION_NOTARIAL><ns2:REQUEST><ns2:CABECERA><ns2:ID_COMUNICACION>2147483647</ns2:ID_COMUNICACION><ns2:FECHA>2016-03-22</ns2:FECHA><ns2:HORA>10:55:00</ns2:HORA><ns2:TIPO_OPERACION>TRANSFERENCIA</ns2:TIPO_OPERACION></ns2:CABECERA><ns2:MENSAJE><ns2:TRANSFERENCIA><ns2:CODIGO_SERVICIO>DEUDAS</ns2:CODIGO_SERVICIO><ns2:REFERENCIA>999988887777666655</ns2:REFERENCIA><ns2:FECHA_EMISION>2016-03-24</ns2:FECHA_EMISION><ns2:FECHA_VALOR>2016-03-25</ns2:FECHA_VALOR><ns2:NOTARIO><ns2:CODIGO_ULTIMAS_VOLUNTADES>9900005</ns2:CODIGO_ULTIMAS_VOLUNTADES><ns2:TIP_DOC_IDENTIFICACION>1</ns2:TIP_DOC_IDENTIFICACION><ns2:NUM_DOC_IDENTIFICACION>11711111H</ns2:NUM_DOC_IDENTIFICACION></ns2:NOTARIO><ns2:IMPORTE>1.00</ns2:IMPORTE><ns2:MONEDA>EUR</ns2:MONEDA><ns2:ORDENANTE>JUAN PEREZ SANCHEZ</ns2:ORDENANTE><ns2:CONCEPTO>Pago deuda inmueble Santurze</ns2:CONCEPTO></ns2:TRANSFERENCIA><ns2:TRANSFERENCIA><ns2:CODIGO_SERVICIO>DEUDAS</ns2:CODIGO_SERVICIO><ns2:REFERENCIA>999988887777666655</ns2:REFERENCIA><ns2:FECHA_EMISION>2016-03-24</ns2:FECHA_EMISION><ns2:FECHA_VALOR>2016-03-25</ns2:FECHA_VALOR><ns2:NOTARIO><ns2:CODIGO_ULTIMAS_VOLUNTADES>9900005</ns2:CODIGO_ULTIMAS_VOLUNTADES><ns2:TIP_DOC_IDENTIFICACION>1</ns2:TIP_DOC_IDENTIFICACION><ns2:NUM_DOC_IDENTIFICACION>11711111H</ns2:NUM_DOC_IDENTIFICACION></ns2:NOTARIO><ns2:IMPORTE>2.00</ns2:IMPORTE><ns2:MONEDA>EUR</ns2:MONEDA><ns2:ORDENANTE>JUAN PEREZ SANCHEZ</ns2:ORDENANTE><ns2:CONCEPTO>Pago deuda inmueble Santurze</ns2:CONCEPTO></ns2:TRANSFERENCIA></ns2:MENSAJE></ns2:REQUEST></ns2:SERVICIO_CONSIGNACION_NOTARIAL></SERVICE_DISPATCHER_REQUEST></soapenv:Body>

使用生成的摘要值,我创建了一个SignedInfo节点:

String xmlDigestFromBody =
            "<ds:SignedInfo xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" 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:CanonicalizationMethod Algorithm=\"http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments\"></ds:CanonicalizationMethod>" 
            + "<ds:SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\"></ds:SignatureMethod>" 
            + "<ds:Reference URI=" + wsuId + ">" 
            + "<ds:Transforms>" 
            + "<ds:Transform Algorithm=\"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:DigestMethod>"
            + "<ds:DigestValue>" 
            + digestValueFromBody 
            + "</ds:DigestValue>" 
            + "</ds:Reference>" 
            + "</ds:SignedInfo>";

签名的xml如下所示:

<ds:SignedInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" 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:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"></ds:CanonicalizationMethod><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod><ds:Reference URI="#id-D1DD0227ECDC46640D147197713960845"><ds:Transforms><ds:Transform Algorithm="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:DigestMethod><ds:DigestValue>Dd7cqOPVujwavDwKWwWqI8NHfYw=</ds:DigestValue></ds:Reference></ds:SignedInfo>

有了这个XML和我的X509证书信息,我使用这个方法来获取符号值:

byte[] signDigest = sign(privateKey, xmlDigestFromBody, algorithm);
String signValueDigest = new BASE64Encoder().encode(signDigest);

// privateKey-> private key from X509 Certificate
// data -> Data to get signed
// algorith -> algorith for sign, in this case with value -> SHA1withRSA
private static byte[] sign(PrivateKey privateKey, String data, String algorithm) throws GeneralSecurityException
{
    Signature signature = Signature.getInstance(algorithm);
    signature.initSign(privateKey);
    signature.update(data.getBytes());
    return signature.sign();
}

使用生成的所有信息,我形成了完整的Soap消息。

String signedSoap = "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" 
            + "<soap:Header>"
            + "<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\" soap:mustUnderstand=\"1\">"
            + "<ds:Signature xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\">" 
            + xmlDigestCXFSoap 
            + "<ds:SignatureValue>" 
            + signValueDigest 
            + "</ds:SignatureValue>" 
            + "<ds:KeyInfo>" + "<wsse:SecurityTokenReference>"
            + "<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\">" 
            + wsseKeyIdentifier
            + "</wsse:KeyIdentifier>" 
            + "</wsse:SecurityTokenReference>" 
            + "</ds:KeyInfo>" 
            + "</ds:Signature>" 
            + "</wsse:Security>" 
            + serviceDispatcher 
            + "</soap:Header>" 
            + "<soap:Body xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\" wsu:Id=" + wsuId+ ">"
            + dataXMLSoap 
            + "</soap:Body>"
            + "</soap:Envelope>";

最后,我收到了这条肥皂剧消息:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><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" soap:mustUnderstand="1"><ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><ds:Reference URI="#id-D1DD0227ECDC46640D147197713960845"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>Dd7cqOPVujwavDwKWwWqI8NHfYw=</ds:DigestValue></ds:Reference></ds:SignedInfo><ds:SignatureValue>U4I0IFFDfpy32vTfpjLQkV10tGOG4XloOaPJPjymFIaV5tzxqd3bAiigghWgELA5WByZ/IqvCL08//BAq+G+ybYn0dwOS+JYZP5ftDow3ZCf5pQNp2DtSnLbLPjswAzcUvR1MfZHbkIhPWOd5fDIs+hPuRs0cq1owfrmXrik0uB48tq6X8bkrl68QMYOXtvi/MGmAIpyjUvXm91ex7YiHpvZG7Jfqn67sL1ca3mWt+14lHeidWZU7qVGCmL0OskIv4uzJO90BthUSlC2B2v+QBRfnL5mTZ+msSK6yI9jRhFazFNe/NG+obRLhns+1Fz/ETtcbdBs4WrLs78tZmcDnA==</ds:SignatureValue><ds:KeyInfo><wsse:SecurityTokenReference><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">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</wsse:KeyIdentifier></wsse:SecurityTokenReference></ds:KeyInfo></ds:Signature></wsse:Security><SERVICE_DISPATCHER xmlns="http://inti.notariado.org/XML" xmlns:ns2="http://ancert.notariado.org/XML/CSN"><TIMESTAMP>2016-08-23T20:32:15.294+02:00</TIMESTAMP><TIPO_MSJ>1</TIPO_MSJ><EMISOR>TEST</EMISOR><RECEP>CGN</RECEP><SERVICIO>CN0001</SERVICIO></SERVICE_DISPATCHER></soap:Header><soap:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="#id-D1DD0227ECDC46640D147197713960845"><SERVICE_DISPATCHER_REQUEST xmlns="http://inti.notariado.org/XML" xmlns:ns2="http://ancert.notariado.org/XML/CSN"><ns2:SERVICIO_CONSIGNACION_NOTARIAL><ns2:REQUEST><ns2:CABECERA><ns2:ID_COMUNICACION>2147483647</ns2:ID_COMUNICACION><ns2:FECHA>2016-03-22</ns2:FECHA><ns2:HORA>10:55:00</ns2:HORA><ns2:TIPO_OPERACION>TRANSFERENCIA</ns2:TIPO_OPERACION></ns2:CABECERA><ns2:MENSAJE><ns2:TRANSFERENCIA><ns2:CODIGO_SERVICIO>DEUDAS</ns2:CODIGO_SERVICIO><ns2:REFERENCIA>999988887777666655</ns2:REFERENCIA><ns2:FECHA_EMISION>2016-03-24</ns2:FECHA_EMISION><ns2:FECHA_VALOR>2016-03-25</ns2:FECHA_VALOR><ns2:NOTARIO><ns2:CODIGO_ULTIMAS_VOLUNTADES>9900005</ns2:CODIGO_ULTIMAS_VOLUNTADES><ns2:TIP_DOC_IDENTIFICACION>1</ns2:TIP_DOC_IDENTIFICACION><ns2:NUM_DOC_IDENTIFICACION>11711111H</ns2:NUM_DOC_IDENTIFICACION></ns2:NOTARIO><ns2:IMPORTE>1.00</ns2:IMPORTE><ns2:MONEDA>EUR</ns2:MONEDA><ns2:ORDENANTE>JUAN PEREZ SANCHEZ</ns2:ORDENANTE><ns2:CONCEPTO>Pago deuda inmueble Santurze</ns2:CONCEPTO></ns2:TRANSFERENCIA><ns2:TRANSFERENCIA><ns2:CODIGO_SERVICIO>DEUDAS</ns2:CODIGO_SERVICIO><ns2:REFERENCIA>999988887777666655</ns2:REFERENCIA><ns2:FECHA_EMISION>2016-03-24</ns2:FECHA_EMISION><ns2:FECHA_VALOR>2016-03-25</ns2:FECHA_VALOR><ns2:NOTARIO><ns2:CODIGO_ULTIMAS_VOLUNTADES>9900005</ns2:CODIGO_ULTIMAS_VOLUNTADES><ns2:TIP_DOC_IDENTIFICACION>1</ns2:TIP_DOC_IDENTIFICACION><ns2:NUM_DOC_IDENTIFICACION>11711111H</ns2:NUM_DOC_IDENTIFICACION></ns2:NOTARIO><ns2:IMPORTE>2.00</ns2:IMPORTE><ns2:MONEDA>EUR</ns2:MONEDA><ns2:ORDENANTE>JUAN PEREZ SANCHEZ</ns2:ORDENANTE><ns2:CONCEPTO>Pago deuda inmueble Santurze</ns2:CONCEPTO></ns2:TRANSFERENCIA></ns2:MENSAJE></ns2:REQUEST></ns2:SERVICIO_CONSIGNACION_NOTARIAL></SERVICE_DISPATCHER_REQUEST></soap:Body></soap:Envelope>

当我在端点(https://test.. .)上使用SoapUI使用此soap消息时,始终收到此响应:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Body>
  <soapenv:Fault>
     <faultcode>soapenv:Server.generalException</faultcode>
     <faultstring>WSDoAllReceiver: security processing failed; nested exception is: 
org.apache.ws.security.WSSecurityException: The signature verification failed</faultstring>
     <detail>
        <ns1:hostname xmlns:ns1="http://xml.apache.org/axis/">hermes4</ns1:hostname>
     </detail>
  </soapenv:Fault>

我有一个OK Soap消息,我使用它在java上生成我的Soap消息,我没有发现与我生成的XML的结构差异。

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Header>
<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" soap:mustUnderstand="1">
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo><ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/><ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/><ds:Reference URI="#id-4A1E576857255EBB5114717876404904"><ds:Transforms><ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/></ds:Transforms><ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/><ds:DigestValue>K2IpilH1NxMSOTeA4yRZukLC2vk=</ds:DigestValue></ds:Reference></ds:SignedInfo>
<ds:SignatureValue>Yua1G4f8OV3M2xJDZZb3b6zr+9Bx4aufbIkzynYiZeHZhzPHwm4vumN7bmdcU0TC9mF7qpC7CkrcbvlIbnG0Wz/PPcJ7iQ0KLyMMqWhc2u56oMwZjJK4FPX6Pc8wFzSoPACP9c9bC0DDX0ZVBMxXkP2/yWVGIxHSL0oqTHK6vfGBRRYGw7mvzqGXtdKxnENE6akYJU8Xqf/QbP1Oh9sJwRBtbhrJfMWomyDn4FoftNQl2pwMf5PCNmsR7Ecc7iIzFpP141MGgYIecZzA0mxOeF4jqJg3Co/VM4etAFpIFT4GMDDj4JD8nKKfVdZ8+9qOCiZsP2MbSon9tPny2xxPDg==</ds:SignatureValue>
<ds:KeyInfo>
<wsse:SecurityTokenReference>
<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">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</wsse:KeyIdentifier>
</wsse:SecurityTokenReference>
</ds:KeyInfo>
</ds:Signature>
</wsse:Security>
<SERVICE_DISPATCHER xmlns="http://inti.notariado.org/XML" xmlns:ns2="http://ancert.notariado.org/XML/CSN">
<TIMESTAMP>2017-08-21T15:53:58.308+02:00</TIMESTAMP>
<TIPO_MSJ>1</TIPO_MSJ>
<EMISOR>TEST</EMISOR>
<RECEP>CGN</RECEP>
<SERVICIO>CN0001</SERVICIO>
</SERVICE_DISPATCHER>
</soap:Header>
<soap:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="id-4A1E576857255EBB5114717876404904"><SERVICE_DISPATCHER_REQUEST xmlns="http://inti.notariado.org/XML" xmlns:ns2="http://ancert.notariado.org/XML/CSN"><ns2:SERVICIO_CONSIGNACION_NOTARIAL><ns2:REQUEST><ns2:CABECERA><ns2:ID_COMUNICACION>2147483647</ns2:ID_COMUNICACION><ns2:FECHA>2016-03-22</ns2:FECHA><ns2:HORA>10:55:00</ns2:HORA><ns2:TIPO_OPERACION>TRANSFERENCIA</ns2:TIPO_OPERACION></ns2:CABECERA><ns2:MENSAJE><ns2:TRANSFERENCIA><ns2:CODIGO_SERVICIO>DEUDAS</ns2:CODIGO_SERVICIO><ns2:REFERENCIA>999988887777666655</ns2:REFERENCIA><ns2:FECHA_EMISION>2016-03-24</ns2:FECHA_EMISION><ns2:FECHA_VALOR>2016-03-25</ns2:FECHA_VALOR><ns2:NOTARIO><ns2:CODIGO_ULTIMAS_VOLUNTADES>9900005</ns2:CODIGO_ULTIMAS_VOLUNTADES><ns2:TIP_DOC_IDENTIFICACION>1</ns2:TIP_DOC_IDENTIFICACION><ns2:NUM_DOC_IDENTIFICACION>11711111H</ns2:NUM_DOC_IDENTIFICACION></ns2:NOTARIO><ns2:IMPORTE>1.00</ns2:IMPORTE><ns2:MONEDA>EUR</ns2:MONEDA><ns2:ORDENANTE>JUAN PEREZ SANCHEZ</ns2:ORDENANTE><ns2:CONCEPTO>Pago deuda inmueble Santurze</ns2:CONCEPTO></ns2:TRANSFERENCIA><ns2:TRANSFERENCIA><ns2:CODIGO_SERVICIO>DEUDAS</ns2:CODIGO_SERVICIO><ns2:REFERENCIA>999988887777666655</ns2:REFERENCIA><ns2:FECHA_EMISION>2016-03-24</ns2:FECHA_EMISION><ns2:FECHA_VALOR>2016-03-25</ns2:FECHA_VALOR><ns2:NOTARIO><ns2:CODIGO_ULTIMAS_VOLUNTADES>9900005</ns2:CODIGO_ULTIMAS_VOLUNTADES><ns2:TIP_DOC_IDENTIFICACION>1</ns2:TIP_DOC_IDENTIFICACION><ns2:NUM_DOC_IDENTIFICACION>11711111H</ns2:NUM_DOC_IDENTIFICACION></ns2:NOTARIO><ns2:IMPORTE>2.00</ns2:IMPORTE><ns2:MONEDA>EUR</ns2:MONEDA><ns2:ORDENANTE>JUAN PEREZ SANCHEZ</ns2:ORDENANTE><ns2:CONCEPTO>Pago deuda inmueble Santurze</ns2:CONCEPTO></ns2:TRANSFERENCIA></ns2:MENSAJE></ns2:REQUEST></ns2:SERVICIO_CONSIGNACION_NOTARIAL></SERVICE_DISPATCHER_REQUEST></soap:Body>
</soap:Envelope>

请有没有人能帮我告诉我我做错了什么。谢谢大家花时间阅读我的提问:)
亲切的问候。

ezykj2lf

ezykj2lf1#

我用我的解决方案回答了我的问题。@pedrofb告诉我一个更好的方法来解决我的问题但我不能在我的WAS服务器上使用。
我使用一个私有方法来规范化我的XML以创建摘要,然后创建签名:

private String canonicalize(String xml)
{
    try
    {
        String CHARSET = "UTF-8";
        Init.init();
        Canonicalizer canon = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_EXCL_WITH_COMMENTS);
        String canoninalizacion = new String(canon.canonicalize(xml.getBytes(CHARSET)), CHARSET);
        return canoninalizacion;
    }
    catch (Exception e)
    {
        e.printStackTrace();
        return xml;
    }
}

然后我们正确地转换XML以在正确的位置设置名称空间和前缀用途:

private String createBodyXML(String dataXML)
{
    String docXML = canonicalize(dataXML);
    // Manual introduction of prefixes
    docXML = docXML.replaceAll("</", "</ns2:").replaceAll("<", "<ns2:").replaceAll("<ns2:/ns2:", "</ns2:");

    String startBodyHash = "<soap:Body xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" Id=\"MsgBody\">";
    String endBodyHash = "</soap:Body>";
    String dataXMLSoap = "<SERVICE_DISPATCHER_REQUEST xmlns=\"http://inti.notariado.org/XML\">" 
        + "<ns2:SERVICIO_CONSIGNACION_NOTARIAL xmlns:ns2=\"http://ancert.notariado.org/XML/CSN\">" 
        + docXML 
        + "</ns2:SERVICIO_CONSIGNACION_NOTARIAL>" 
        + "</SERVICE_DISPATCHER_REQUEST>";

    String xmlHash = startBodyHash + dataXMLSoap + endBodyHash;
    // this xmlHash is the same body of the SOAP call
    return xmlHash;
}

我们在创建XML的时候所做的body和XML的signedInfo.is并不是最好的制作方法:

String xmlDigest = "<ds:SignedInfo xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">" 
            + "<ds:CanonicalizationMethod Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\">"
            + "<ec:InclusiveNamespaces xmlns:ec=\"http://www.w3.org/2001/10/xml-exc-c14n#\" PrefixList=\"soap\"></ec:InclusiveNamespaces>" 
            + "</ds:CanonicalizationMethod>" 
            + "<ds:SignatureMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#rsa-sha1\"></ds:SignatureMethod>"
            + "<ds:Reference URI=\"#MsgBody\">" 
            + "<ds:Transforms>" 
            + "<ds:Transform Algorithm=\"http://www.w3.org/2001/10/xml-exc-c14n#\">" 
            + "<ec:InclusiveNamespaces xmlns:ec=\"http://www.w3.org/2001/10/xml-exc-c14n#\" PrefixList=\"\"></ec:InclusiveNamespaces>" 
            + "</ds:Transform>"
            + "</ds:Transforms>" 
            + "<ds:DigestMethod Algorithm=\"http://www.w3.org/2000/09/xmldsig#sha1\"></ds:DigestMethod>" 
            + "<ds:DigestValue>" 
            + digestValue 
            + "</ds:DigestValue>" 
            + "</ds:Reference>" 
            + "</ds:SignedInfo>";

我想和大家分享一下我是如何调用带有良好签名的SOAP消息的Web服务的,它与这个问题无关,但可能对某些人有用:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Authenticator;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.PasswordAuthentication;
import java.net.ProtocolException;
import java.net.Proxy;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
...
private String sendMessage(String xmlAEnviar) throws Exception
{
    try
    {
        // Metodo envio
        String POST = "POST";
        String urlEndpoint = "https://test.dominio.org/servicedispatcher/services/ServiceDispatcherSigned";
        final String httpsProxyHost = "180.100.14.70";
        final String httpsProxyPort = "8080";
        final String userProxy = "user";
        final String passProxy = "password";

        URL httpsURL = new URL(urlEndpoint);

        HttpsURLConnection httpsURLConnection = null;

        if (httpsProxyHost.length() > 0 && httpsProxyPort.length() > 0)
        {
            Proxy miProxy = new Proxy(java.net.Proxy.Type.HTTP, new InetSocketAddress(httpsProxyHost, Integer.parseInt(httpsProxyPort)));
            httpsURLConnection = (HttpsURLConnection) httpsURL.openConnection(miProxy);
            if (userProxy.length() > 0 && passProxy.length() > 0)
            {
                String userPassword = userProxy + ":" + passProxy;
                sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
                String encodedLogin = encoder.encode(userPassword.getBytes());
                Authenticator.setDefault(new Authenticator()
                {
                    protected PasswordAuthentication getPasswordAuthentication()
                    {
                        return new PasswordAuthentication(userProxy, passProxy.toCharArray());
                    }
                });
                httpsURLConnection.setRequestProperty("Proxy-Authorization", (new StringBuilder("Basic ")).append(encodedLogin).toString());
            }
        }

        else
        {
            httpsURLConnection = (HttpsURLConnection) httpsURL.openConnection();
        }

        httpsURLConnection.setDoOutput(true);
        httpsURLConnection.setRequestMethod(POST);
        httpsURLConnection.setRequestProperty("Content-Type", "text/xml; charset=\"UTF-8\"");
        httpsURLConnection.setRequestProperty("SOAPAction", "");

        OutputStream outputStream = httpsURLConnection.getOutputStream();
        outputStream.write(xmlAEnviar.getBytes());
        outputStream.flush();

        InputStream httpsInputStream = httpsURLConnection.getInputStream();
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader((httpsInputStream)));
        String lineanext = "";
        String outputnext = "";
        while ((lineanext = bufferedReader.readLine()) != null)
        {
            outputnext = outputnext.concat(lineanext);
        }
        httpsURLConnection.disconnect();

        return outputnext;
    }
    catch (NumberFormatException e)
    {
        e.printStackTrace();
        throw new Exception(e);
    }
    catch (MalformedURLException e)
    {
        e.printStackTrace();
        throw new Exception(e);
    }
    catch (ProtocolException e)
    {
        e.printStackTrace();
        throw new Exception(e);
    }
    catch (IOException e)
    {
        e.printStackTrace();
        throw new Exception(e);
    }
}

感谢所有人,尤其是@pedrofb。
亲切的问候。

4uqofj5v

4uqofj5v2#

SOAP Enveloped signature:使用限定凭证签署XML文件。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
<!-- <env:Header /> -->
    <env:Body>
       <product version="11.1.2.4.0"> <!-- Data XML -->
           <name>API Gateway</name>
           <company>Oracle</company>
           <description>SOA Security and Management</description>
       </product>
    </env:Body>
</env:Envelope>

通过使用以下函数,您可以使用证书和私钥对XML进行数字签名Baeldung.cer, Baeldung.p12(password =“password”)

public static Document getDigitalSignDoc(String sourceFile) throws Exception {

    Document doc = SOAP_Security_Signature.getDocument(sourceFile, false);
    String signatureID = "123", keyInfoID = "456", referenceID = "Id-0000011a101b167c-0000000000000012";
    //optional, but better
    Element signElementEnvelope = doc.getDocumentElement();
    //signElement.normalize();
    
    String nameSpace = "env"; //soap
    Node itemBody = signElementEnvelope.getElementsByTagName(nameSpace+":Body").item(0);
    Node itemHead = signElementEnvelope.getElementsByTagName(nameSpace+":Header").item(0);
    if (itemHead == null) {
        System.out.println("Provided SOAP XML does not contains any Header part. So creating it.");
        Element createElement = doc.createElement(nameSpace+":Header");
        signElementEnvelope.insertBefore(createElement, itemBody);
        
        itemHead = signElementEnvelope.getElementsByTagName(nameSpace+":Header").item(0);
    }
    ((Element)itemBody).setAttribute("Id", referenceID);
    
    
    String elementRefId = "#" + referenceID;
    
    Node firstChild = itemBody.getFirstChild();
    Document dataDoc = firstChild.getOwnerDocument(); // Total Entire XML
    System.out.println("Document: "+dataDoc.getDocumentElement());
    
    org.apache.xml.security.Init.init();
    org.apache.xml.security.signature.XMLSignature signature = new XMLSignature(dataDoc, elementRefId, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1);
    //XMLSignature signature = new XMLSignature(dataDoc, elementRefId, XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1, Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS);
    itemHead.appendChild(signature.getElement());
    
    // Below code adds Sign element after Body tag: </soap:Body><ds:Signature> ... </ds:Signature></soap:Envelope>
    //signElement.appendChild(signature.getElement());
    
    Transforms transforms = new Transforms(signElementEnvelope.getOwnerDocument()); // doc | signElement.getOwnerDocument()
    // <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform>
    transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE); // TRANSFORM_C14N_OMIT_COMMENTS
    //transforms.addTransform(Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS);
    
    //Sign the content of SOAP Envelope
    signature.addDocument(elementRefId, transforms, Constants.ALGO_ID_DIGEST_SHA1);

    //Signing procedure
    signature.setId(signatureID);
    signature.addKeyInfo(loadPublicKeyX509);
    signature.addKeyInfo(loadPublicKeyX509.getPublicKey());
    
    KeyInfo keyInfo = signature.getKeyInfo();
    keyInfo.setId(keyInfoID);
    
    System.out.println("Start signing");
    signature.sign(privateKey);
    
    System.out.println("Finished signing : "+signature.getId());
    return doc;
}

生成的SOAP签名XML文件:

<env:Envelope
    xmlns:env="http://www.w3.org/2003/05/soap-envelope">
    <env:Header>
        <ds:Signature
            xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="123">
            <ds:SignedInfo>
                <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"></ds:CanonicalizationMethod>
                <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"></ds:SignatureMethod>
                <ds:Reference URI="#Id-0000011a101b167c-0000000000000012">
                    <ds:Transforms>
                        <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"></ds:Transform>
                    </ds:Transforms>
                    <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></ds:DigestMethod>
                    <ds:DigestValue>Fk4qf2xFlZoM2jo9NA+6GkCwKfU=</ds:DigestValue>
                </ds:Reference>
            </ds:SignedInfo>
            <ds:SignatureValue>
VecBSDUFpBBcjLS1AK41NDwUvFl9mHktx2TqqcBtGQpNxMiJv/eRvApeKiHLp8iyVKqbcog4akxp
N6qBGEwOgThYlWdgVSPDct8l42+4XHLxUee5YcUVeW71r4mIuvoT0o9aLtNcjE7xzDeke3rzbOyz
7UORAqyuEe1rVk7QHNEZrW1nZRI9JadAuSboa1ZLI8BK0JqUZD/0UhswLXUtftYAA+2qeWQGRMAk
1RZsC4sfXqmp2oni/wihR+8HkEaiUfpTMq2Gcpnf3a59v67h4fxDtnYlAdN8LX53YHgB+0ONcIxO
vHt88hCLwKiaIeM4Wz7qzMMSmq9/dGBlqFU8Dw==
</ds:SignatureValue>
            <ds:KeyInfo Id="456">
                <ds:X509Data>
                    <ds:X509Certificate>
MIIDPjCCAiagAwIBAgIJAPvd1gx14C3CMA0GCSqGSIb3DQEBBQUAMEcxCzAJBgNVBAYTAk1BMRAw
DgYDVQQIEwdNb3JvY2NvMRMwEQYDVQQHEwpDYXNhYmxhbmNhMREwDwYDVQQDEwhCYWVsZHVuZzAe
Fw0xNzEwMTIxMDQzMTRaFw0yNzEwMTMxMDQzMTRaMEcxCzAJBgNVBAYTAk1BMRAwDgYDVQQIEwdN
b3JvY2NvMRMwEQYDVQQHEwpDYXNhYmxhbmNhMREwDwYDVQQDEwhCYWVsZHVuZzCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBAMyi5GmOeN4QaH/CP5gSOyHX8znb5TDHWV8wc+ZT7kNU8zt5
tGMhjozK6hax155/6tOsBDR0rSYBhL+Dm/+uCVS7qOlRHhf6cNGtzGF1gnNJB2WjI8oMAYm24xpL
j1WphKUwKrn3nTMPnQup5OoNAMYl99flANrRYVjjxrLQvDZDUio6IujrCZ2TtXGM0g/gP++28KT7
g1KlUui3xtB0u33wx7UN8Fix3JmjOaPHGwxGpwP3VGSjfs8cuhqVwRQaZpCOoHU/P8wpXKw80sSd
hz+SRueMPtVYqK0CiLL5/O0h0Y3le4IVwhgg3KG1iTGOWn60UMFn1EYmQ18k5Nsma6UCAwEAAaMt
MCswCQYDVR0TBAIwADARBglghkgBhvhCAQEEBAMCBPAwCwYDVR0PBAQDAgUgMA0GCSqGSIb3DQEB
BQUAA4IBAQC8DDBmJ3p4xytxBiE0s4p1715WT6Dm/QJHp0XC0hkSoyZKDh+XVmrzm+J3SiW1vpsw
b5hLgPo040YX9jnDmgOD+TpleTuKHxZRYj92UYWmdjkWLVtFMcvOh+gxBiAPpHIqZsqo8lfcyAuh
8Jx834IXbknfCUtERDLG/rU9P/3XJhrM2GC5qPQznrW4EYhUCGPyIJXmvATMVvXMWCtfogAL+n42
vjYXQXZoAWomHhLHoNbSJUErnNdWDOh4WoJtXJCxA6U5LSBplqb3wB2hUTqw+0admKltvmy+KA1P
D7OxoGiY7V544zeGqJam1qxUia7y5BL6uOa/4ShSV8pcJDYz
</ds:X509Certificate>
                </ds:X509Data>
                <ds:KeyValue>
                    <ds:RSAKeyValue>
                        <ds:Modulus>
zKLkaY543hBof8I/mBI7IdfzOdvlMMdZXzBz5lPuQ1TzO3m0YyGOjMrqFrHXnn/q06wENHStJgGE
v4Ob/64JVLuo6VEeF/pw0a3MYXWCc0kHZaMjygwBibbjGkuPVamEpTAqufedMw+dC6nk6g0AxiX3
1+UA2tFhWOPGstC8NkNSKjoi6OsJnZO1cYzSD+A/77bwpPuDUqVS6LfG0HS7ffDHtQ3wWLHcmaM5
o8cbDEanA/dUZKN+zxy6GpXBFBpmkI6gdT8/zClcrDzSxJ2HP5JG54w+1ViorQKIsvn87SHRjeV7
ghXCGCDcobWJMY5afrRQwWfURiZDXyTk2yZrpQ==
</ds:Modulus>
                        <ds:Exponent>AQAB</ds:Exponent>
                    </ds:RSAKeyValue>
                </ds:KeyValue>
            </ds:KeyInfo>
        </ds:Signature>
    </env:Header>
    <env:Body Id="Id-0000011a101b167c-0000000000000012">
        <product version="11.1.2.4.0">
            <name>API Gateway</name>
            <company>Oracle</company>
            <description>SOA Security and Management</description>
        </product>
    </env:Body>
</env:Envelope>

使用公钥证书验证XML的签名

public static boolean isSOAPXmlDigitalSignatureValid(String signedXmlFilePath, PublicKey publicKey) throws Exception {
    String xmlContent = SOAP_Security_Signature.getFileString(signedXmlFilePath);
    
    Document doc = SOAP_Security_Signature.getDocument(xmlContent.trim(), true);
    System.out.println("Document: "+doc.getDocumentElement());
    
    // namespaceURI=http://www.w3.org/2000/09/xmldsig#", localName=Signature
    String localName = "Signature";
    String qualifiedName = "ds";
    doc.createElementNS(javax.xml.crypto.dsig.XMLSignature.XMLNS, qualifiedName); 
    NodeList nl = doc.getElementsByTagNameNS(javax.xml.crypto.dsig.XMLSignature.XMLNS, localName); // "Signature"
    if (nl.getLength() == 0) {
        throw new Exception("No XML Digital Signature Found, document is discarded");
    }
    Node sigElement = nl.item(0);
    
    org.apache.xml.security.Init.init();
    org.apache.xml.security.signature.XMLSignature signature = new XMLSignature((Element) sigElement, "");
    return signature.checkSignatureValue(publicKey);
}

完整示例:此类SOAP_Security_Signature中使用的一些函数

//dependency: groupId:xml-security, artifactId:xmlsec, version:1.3.0
//dependency: groupId:xalan, artifactId:xalan, version:2.7.1
public class SOAP_XML_Signature {

    static PrivateKey privateKey;
    static X509Certificate loadPublicKeyX509;
    static String path = "C:/Yash/SOAP/", privateKeyFilePath = path+"Baeldung.p12", publicKeyFilePath = path+"Baeldung.cer",
                  inputFile= path+"Soap1.xml", outputFile = path+"output.xml";
    public static void main(String unused[]) throws Exception {
        
        InputStream pkcs_FileStream = new FileInputStream(privateKeyFilePath);
        privateKey = SOAP_Security_Signature.loadPrivateKeyforSigning(pkcs_FileStream, "password");
        System.out.println("privateKey : "+privateKey);
        
        InputStream cerFileStream = new FileInputStream(publicKeyFilePath);
        loadPublicKeyX509 = SOAP_Security_Signature.loadPublicKeyX509(cerFileStream);
        PublicKey publicKey = loadPublicKeyX509.getPublicKey();
        System.out.println("loadPublicKey : "+ publicKey);
        
        //SOAP envelope to be signed
        Document digitalSignDoc = getDigitalSignDoc(inputFile);

        File signatureFile = new File(outputFile);
        String BaseURI = signatureFile.toURI().toURL().toString();
        //write signature to file
        FileOutputStream f = new FileOutputStream(signatureFile);
        XMLUtils.outputDOMc14nWithComments(digitalSignDoc, f);
        f.close();
        System.out.println("Wrote signature to " + BaseURI);
        
        boolean soapXmlDigitalSignatureValid = isSOAPXmlDigitalSignatureValid(outputFile, publicKey);
        System.out.println("isSOAPXmlDigitalSignatureValid :"+soapXmlDigitalSignatureValid);
    }

}
s6fujrry

s6fujrry3#

您需要执行兼容的ws-security SOAP消息,其中包含XML DSig Signature
您没有正确构建消息摘要,也没有应用规范化方法和转换。Java本身支持XML signatures。您不需要从头构建它们。
在本post中,您将找到一个使用标准Java代码的示例和一个指向应用服务器实用程序的链接(推荐)

jslywgbw

jslywgbw4#

我正在改进https://stackoverflow.com/a/63617195/5845739Yash的回答,谢谢你的精彩回答。
此外,我将直接调用SOAP消息,而不是在

callTheWebServiceFromFile()

Maven依赖项

<dependency>
            <groupId>org.bouncycastle</groupId>
            <artifactId>bcprov-jdk15on</artifactId>
            <version>1.70</version>
        </dependency>

        <dependency>
            <groupId>xalan</groupId>
            <artifactId>xalan</artifactId>
            <version>2.7.1</version>
        </dependency>
        <dependency>
            <groupId>xml-security</groupId>
            <artifactId>xmlsec</artifactId>
            <version>1.3.0</version>
        </dependency>

Java完整代码

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Scanner;

import javax.xml.crypto.dom.DOMStructure;
import javax.xml.crypto.dsig.Reference;
import javax.xml.crypto.dsig.SignedInfo;
import javax.xml.crypto.dsig.Transform;
import javax.xml.crypto.dsig.XMLSignatureFactory;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import javax.xml.crypto.dsig.spec.TransformParameterSpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeader;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.xml.security.c14n.Canonicalizer;
import org.apache.xml.security.transforms.Transforms;
import org.apache.xml.security.utils.Constants;
import org.springframework.http.HttpHeaders;
import org.w3c.dom.Document;
import org.xml.sax.InputSource;
public class SOAP_Security_Signature {
    static final String 
    WSSE_NS = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
    WSU_NS  = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd",
    DSIG_NS = "http://www.w3.org/2000/09/xmldsig#", // javax.xml.crypto.dsig.XMLSignature.XMLNS, Constants.SignatureSpecNS
    
    binarySecurityToken_Encoding = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary",
    binarySecurityToken_Value = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3",
    
    signatureMethodAlog_SHA1 = DSIG_NS + "rsa-sha1", // XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1
    digestMethodAlog_SHA1  = Constants.ALGO_ID_DIGEST_SHA1, // DSIG_NS + "sha1", // Constants.ALGO_ID_DIGEST_SHA1
    transformAlog = Transforms.TRANSFORM_C14N_EXCL_OMIT_COMMENTS, //"http://www.w3.org/2001/10/xml-exc-c14n#";
    canonicalizerAlog = Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS; //"http://www.w3.org/2001/10/xml-exc-c14n#"; CanonicalizationMethod.EXCLUSIVE
    
    static {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
    }
    public static X509Certificate loadPublicKeyX509(InputStream cerFileStream) throws CertificateException, NoSuchProviderException {
        CertificateFactory  certificateFactory = CertificateFactory.getInstance("X.509", "BC");
        X509Certificate x509Certificate = (X509Certificate) certificateFactory.generateCertificate(cerFileStream);
        return x509Certificate;
    }
    public static PrivateKey loadPrivateKeyforSigning(InputStream cerFileStream, String password) throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, NoSuchProviderException {
        KeyStore keyStore = KeyStore.getInstance("PKCS12"); //, "BC");
        keyStore.load(cerFileStream, password.toCharArray());
        
        Enumeration<String> keyStoreAliasEnum = keyStore.aliases();
        PrivateKey privateKey = null;
        String alias = null;
        if ( keyStoreAliasEnum.hasMoreElements() ) {
            alias = keyStoreAliasEnum.nextElement();
            if (password != null) {
                privateKey = (PrivateKey) keyStore.getKey(alias, password.toCharArray());
            }
        }
        return privateKey;
    }
    static X509Certificate loadPublicKeyX509;
    static PrivateKey privateKey;
    static String  privateKeyFilePath = "pfxFileLocation/Ibtsam.pfx", publicKeyFilePath = "crtFileLocation/Ibtsam.crt",
                  inputFile= "sourceFileLocation/x.xml", outputFile = "destinationFileLocation/output.xml";
    public static void main(String[] args) throws Exception {
        
        InputStream pkcs_FileStream = new FileInputStream(privateKeyFilePath);
        privateKey = loadPrivateKeyforSigning(pkcs_FileStream, "password");//Password of PFX file
        System.out.println("privateKey : "+privateKey);
        
        InputStream cerFileStream = new FileInputStream(publicKeyFilePath);
        loadPublicKeyX509 = loadPublicKeyX509(cerFileStream);
        PublicKey publicKey = loadPublicKeyX509.getPublicKey();
        System.out.println("loadPublicKey : "+ publicKey);
        
        System.setProperty("javax.xml.soap.MessageFactory", "com.sun.xml.internal.messaging.saaj.soap.ver1_2.SOAPMessageFactory1_2Impl");
        System.setProperty("javax.xml.bind.JAXBContext", "com.sun.xml.internal.bind.v2.ContextFactory");
        
        SOAPMessage soapMsg = WS_Security_signature(inputFile, false);
        outputSOAPMessageToFile(soapMsg);
        /*ByteArrayOutputStream out = new ByteArrayOutputStream();
        soapMsg.writeTo(out);
        String strMsg = new String(out.toByteArray());
        System.out.println("+++++++++++++++++++++++++++++++++++");
        System.out.println(strMsg);
        System.out.println("+++++++++++++++++++++++++++++++++++");*/
        new SOAP_Security_Signature().callTheWebServiceFromFile(soapMsg);
        //System.out.println("Signature Succesfull. Verify the Signature");
       // boolean soapXmlWSSEDigitalSignatureValid = isSOAPXmlWSSEDigitalSignatureValid(outputFile, publicKey);
       // System.out.println("isSOAPXmlDigitalSignatureValid :"+soapXmlWSSEDigitalSignatureValid);
    }
  
    
    public static void outputSOAPMessageToFile(SOAPMessage soapMessage) throws SOAPException, IOException {
        File outputFileNew = new File(outputFile);
        java.io.FileOutputStream fos = new java.io.FileOutputStream(outputFileNew);
        soapMessage.writeTo(fos);
        fos.close();
    }
    
    public static String toStringDocument(Document doc) throws TransformerException {
        StringWriter sw = new StringWriter();
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer transformer = tf.newTransformer();
        transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
        transformer.setOutputProperty(OutputKeys.METHOD, "xml");
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");

        transformer.transform(new DOMSource(doc), new StreamResult(sw));
        return sw.toString();
    }
    public static String getFileString(String xmlFilePath) throws FileNotFoundException {
        File file = new File(xmlFilePath);
        //FileInputStream parseXMLStream = new FileInputStream(file.getAbsolutePath());
        
        Scanner scanner = new Scanner( file, "UTF-8" );
        String xmlContent = scanner.useDelimiter("\\A").next();
        scanner.close(); // Put this call in a finally block
        System.out.println("Str:"+xmlContent);
        return xmlContent;
    }
    public static Document getDocument(String xmlData, boolean isXMLData) throws Exception {
        DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
        dbFactory.setNamespaceAware(true);
        dbFactory.setIgnoringComments(true);
        DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
        Document doc;
        if (isXMLData) {
            InputSource ips = new org.xml.sax.InputSource(new StringReader(xmlData));
            doc = dBuilder.parse(ips);
        } else {
            doc = dBuilder.parse( new File(xmlData) );
        }
        return doc;
    }
 
    private void callTheWebServiceFromFile(SOAPMessage msg) throws IOException, SOAPException {
         ByteArrayOutputStream out = new ByteArrayOutputStream();
        msg.writeTo(out);
        
        // Set the soapPart Content with the stream source
        //soapPart.setContent(ss);
        SOAPPart soapPart = msg.getSOAPPart();
        
        // Create a webService connection
        SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
        SOAPConnection soapConnection = soapConnectionFactory.createConnection();

        // Invoke the webService.
        String soapEndpointUrl = "https://mirsal2gwytest.dubaitrade.ae/customsb2g/oilfields";
        SOAPMessage resp = soapConnection.call(msg, soapEndpointUrl);

        // Reading result
        resp.writeTo(System.out);

        //fis.close();
        soapConnection.close();
    }

    
    public static SOAPMessage WS_Security_signature(String inputFile, boolean isDataXML) throws Exception {
        SOAPMessage soapMsg;
        Document docBody;
        if (isDataXML) {
            System.out.println("Sample DATA xml - Create SOAP Message");
            MessageFactory messageFactory = MessageFactory.newInstance();
            SOAPMessage soapMessage = messageFactory.createMessage();
            soapMsg = soapMessage;
            
            String xmlContent = getFileString(inputFile);
            docBody = getDocument(xmlContent.trim(), true);
            System.out.println("Data Document: "+docBody.getDocumentElement());
        } else {
            System.out.println("SOAP XML with Envelope");
            
            Document doc = getDocument(inputFile, false); // SOAP MSG removing comment elements
            String docStr = toStringDocument(doc); // https://stackoverflow.com/a/2567443/5081877
            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(docStr.getBytes());
            
            MimeHeaders mimeHeaders = new MimeHeaders();
            mimeHeaders.removeHeader("Content-Type");
            mimeHeaders.addHeader(HttpHeaders.CONTENT_TYPE, "text/xml;charset=utf-8");
            mimeHeaders.addHeader("SOAPAction", "process");
            SOAPMessage message = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL).createMessage(mimeHeaders, byteArrayInputStream);
            soapMsg = message;
            
            docBody = soapMsg.getSOAPBody().extractContentAsDocument();
            System.out.println("SOAP DATA Document: "+docBody.getDocumentElement());
        }
        // A new SOAPMessage object contains: •SOAPPart object •SOAPEnvelope object •SOAPBody object •SOAPHeader object 
        SOAPPart soapPart = soapMsg.getSOAPPart();
        soapPart.setMimeHeader("Content-Type", "text/xml;charset=UTF-8");
        SOAPEnvelope soapEnv = soapPart.getEnvelope();
        SOAPHeader soapHeader = soapEnv.getHeader(); // soapMessage.getSOAPHeader();
        SOAPBody soapBody = soapEnv.getBody(); // soapMessage.getSOAPBody()
        
        soapBody.addDocument(docBody);
        soapBody.addAttribute(soapEnv.createName("Id", "wsu", WSU_NS), "Body");
        
        if (soapHeader == null) {
            soapHeader = soapEnv.addHeader();
            System.out.println("Provided SOAP XML does not contains any Header part. So creating it.");
        }
        // <wsse:Security> element adding to Header Part
        SOAPElement securityElement = soapHeader.addChildElement("Security", "wsse", WSSE_NS);
        securityElement.addNamespaceDeclaration("wsu", WSU_NS);

        String certEncodedID = "X509Token", timeStampID = "TS", signedBodyID = "Body";
        // (ii) Add Binary Security Token.
        // <wsse:BinarySecurityToken EncodingType="...#Base64Binary" ValueType="...#X509v3" wsu:Id="X509Token">The base64 encoded value of the ROS digital certificate.</wsse:BinarySecurityToken>
        SOAPElement binarySecurityToken = securityElement.addChildElement("BinarySecurityToken", "wsse");
        binarySecurityToken.setAttribute("ValueType", binarySecurityToken_Value);
        binarySecurityToken.setAttribute("EncodingType", binarySecurityToken_Encoding);
        binarySecurityToken.setAttribute("wsu:Id", certEncodedID);
            byte[] certByte = loadPublicKeyX509.getEncoded();
            String encodeToString = Base64.getEncoder().encodeToString(certByte);
        binarySecurityToken.addTextNode(encodeToString);
        
        //(iii) Add TimeStamp element - <wsu:Timestamp wsu:Id="TS">
        SOAPElement timestamp = securityElement.addChildElement("Timestamp", "wsu");
        timestamp.addAttribute(soapEnv.createName("Id", "wsu", WSU_NS), timeStampID);
            String DATE_TIME_PATTERN = "yyyy-MM-dd'T'HH:mm:ss.SSSX";
            DateTimeFormatter timeStampFormatter = DateTimeFormatter.ofPattern(DATE_TIME_PATTERN);
        timestamp.addChildElement("Created", "wsu").setValue(timeStampFormatter.format(ZonedDateTime.now().toInstant().atZone(ZoneId.of("UTC"))));
        timestamp.addChildElement("Expires", "wsu").setValue(timeStampFormatter.format(ZonedDateTime.now().plusSeconds(30).toInstant().atZone(ZoneId.of("UTC"))));

        // (iv) Add signature element
        // <wsse:Security> <ds:Signature> <ds:KeyInfo> <wsse:SecurityTokenReference>
        SOAPElement securityTokenReference = securityElement.addChildElement("SecurityTokenReference", "wsse");
        SOAPElement reference = securityTokenReference.addChildElement("Reference", "wsse");
        reference.setAttribute("URI", "#"+certEncodedID); // <wsse:BinarySecurityToken wsu:Id="X509Token"
        
        // <ds:SignedInfo>
        String providerName = System.getProperty("jsr105Provider", "org.jcp.xml.dsig.internal.dom.XMLDSigRI");
        XMLSignatureFactory xmlSignatureFactory = XMLSignatureFactory.getInstance("DOM", (java.security.Provider) Class.forName(providerName).newInstance());

        //Digest method - <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
        javax.xml.crypto.dsig.DigestMethod digestMethod = xmlSignatureFactory.newDigestMethod(digestMethodAlog_SHA1, null);
        
        ArrayList<Transform> transformList = new ArrayList<Transform>();
        //Transform - <ds:Reference URI="#Body">
        Transform envTransform = xmlSignatureFactory.newTransform(transformAlog, (TransformParameterSpec) null);
        transformList.add(envTransform);
            //References <ds:Reference URI="#Body">
            ArrayList<Reference> refList = new ArrayList<Reference>();
                Reference refTS   = xmlSignatureFactory.newReference("#"+timeStampID,  digestMethod, transformList, null, null);
                Reference refBody = xmlSignatureFactory.newReference("#"+signedBodyID, digestMethod, transformList, null, null);
            refList.add(refBody);
            refList.add(refTS);

        javax.xml.crypto.dsig.CanonicalizationMethod cm = xmlSignatureFactory.newCanonicalizationMethod(canonicalizerAlog, (C14NMethodParameterSpec) null);

        javax.xml.crypto.dsig.SignatureMethod sm = xmlSignatureFactory.newSignatureMethod(signatureMethodAlog_SHA1, null);
        SignedInfo signedInfo = xmlSignatureFactory.newSignedInfo(cm, sm, refList);

        DOMSignContext signContext = new DOMSignContext(privateKey, securityElement);
        signContext.setDefaultNamespacePrefix("ds");
        signContext.putNamespacePrefix(DSIG_NS, "ds");
        signContext.putNamespacePrefix(WSU_NS, "wsu");

        signContext.setIdAttributeNS(soapBody, WSU_NS, "Id");
        signContext.setIdAttributeNS(timestamp, WSU_NS, "Id");

        KeyInfoFactory keyFactory = KeyInfoFactory.getInstance();
        DOMStructure domKeyInfo = new DOMStructure(securityTokenReference);
        javax.xml.crypto.dsig.keyinfo.KeyInfo keyInfo = keyFactory.newKeyInfo(java.util.Collections.singletonList(domKeyInfo));
        javax.xml.crypto.dsig.XMLSignature signature = xmlSignatureFactory.newXMLSignature(signedInfo, keyInfo);
        signContext.setBaseURI("");

        signature.sign(signContext);
        return soapMsg;
    }
    
}

相关问题