我必须使用java签署Soap消息,但我不能在我的websphere服务器上使用WSS4J,SAAJ,AXIS2或CXF来解决类路径问题。
我必须签署SOAP调用的正文消息。
我为soap消息正确生成了一个带有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>
然后我使用Hash值来创建摘要值,使用前面带有body开始和结束标记的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>
生成teh摘要值后,我创建了一个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();
}
生成所有信息后,我形成了完整的肥皂消息。
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>
请有人帮我告诉我我做错了什么。 感谢大家花时间阅读我的问题:)
亲切的问候。
答案 0 :(得分:1)
我用我的解决方案回答了我的问题。 @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;
}
我们在创建了signedInfo的body和XML的XML时。不是最好的方法:
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。
亲切的问候。
答案 1 :(得分:0)
您需要执行包含ws-security
的合规XML DSig Signature SOAP消息您没有正确构建消息摘要,并且您不应用规范化方法也不会转换。 Java本身支持XML signatures。您不需要从头开始构建它们。
在这个post中,您将找到使用标准Java代码和应用程序服务器实用程序链接的示例(推荐)
答案 2 :(得分:0)
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>
通过使用以下功能,您可以使用证书和私钥Baeldung.cer, Baeldung.p12(密码=“密码”)对XML进行数字签名
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);
}
}