SOAP XML WS-Security签名验证 [英] SOAP XML WS-Security signature verification

查看:277
本文介绍了SOAP XML WS-Security签名验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我能够使用WS-Security签名的证书对SOAP XML进行签名。但我无法验证其签名。在验证签名会导致异常时,将需要一些帮助来解决此问题


SOAP封装的WS-Security签名

 < s:Envelope xmlns:s =" http://schemas.xmlsoap.org/soap/envelope/" 
< s:Header>
< ws:Security xmlns:ws =" http://schemas.xmlsoap.org/..." s:actor = test
< dsig:Signature xmlns:dsig = http://www.w3.org/2000/09 / ... id = Sample
...
< / dsig:Signature>
< / ws:Security>
< / s:Header>
< s:Body>
...
< / s:Body>
< / s:信封>

当我尝试验证SOAP XML时,出现以下异常:


org.apache.xml.security.signature.MissingResourceFailureException:URI #Body的引用没有XMLSignatureInput



  public static boolean isSOAPXmlWSSEDigitalSignatureValid(StringsignedXmlFilePath,PublicKey publicKey)抛出异常{
String xmlContent = getFileString(signedXmlFilePath);

DocumentsignedDoc = getDocument(xmlContent.trim(),true);
signedDoc.createElementNS(DSIG_NS, ds); // qualifiedName = ds;
signatureDoc.createElementNS(WSU_NS, wsu);
signedDoc.createElementNS(WSSE_NS, wsse);

//加载签名
NodeList signatureNodes = signedDoc.getElementsByTagNameNS(javax.xml.crypto.dsig.XMLSignature.XMLNS, Signature);
if(signatureNodes.getLength()== 0){
抛出新的异常(未找到XML数字签名,文档被丢弃);
}

Element sigElement =(Element)signatureNodes.item(0);
if(sigElement == null)
抛出new Exception( Signature元素为null!);

org.apache.xml.security.Init.init();
org.apache.xml.security.signature.XMLSignature签名=新的XMLSignature(sigElement,);
return signature.checkSignatureValue(publicKey);
}

通过使用以下功能,我可以对XML进行签名

 公共静态SOAPMessage WS_Security_signature(String inputFile,boolean isDataXML)引发异常{
SOAPMessage soapMsg;
文件docBody;
if(isDataXML){
System.out.println(示例数据xml-创建SOAP消息);
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage soapMessage = messageFactory.createMessage();
soapMsg = soapMessage;

字符串xmlContent = getFileString(inputFile);
docBody = getDocument(xmlContent.trim(),true);
System.out.println(数据文档: + docBody.getDocumentElement());
} else {
System.out.println(带有信封的SOAP XML);

文档doc = getDocument(inputFile,false); // SOAP MSG删除注释元素
String docStr = toStringDocument(doc); // https://stackoverflow.com/a/2567443/5081877
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(docStr.getBytes());

MimeHeaders mimeHeaders =新的MimeHeaders();
// SOAPMessage消息= MessageFactory.newInstance()。createMessage(null,fileInputStream);
SOAPMessage消息= MessageFactory.newInstance( SOAP 1.2协议).createMessage(mimeHeaders,byteArrayInputStream);
soapMsg =消息;

docBody = soapMsg.getSOAPBody()。extractContentAsDocument();
System.out.println( SOAP DATA Document: + docBody.getDocumentElement());
}
//一个新的SOAPMessage对象包含:•SOAPPart对象•SOAPEnvelope对象•SOAPBody对象•SOAPHeader对象
SOAPPart soapPart = soapMsg.getSOAPPart();
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(提供的SOAP XML不包含任何Header部分。因此创建它。);
}
//< wsse:Security>添加到标题部分
的元素SOAPElement securityElement = soapHeader.addChildElement( Security, wsse,WSSE_NS);
securityElement.addNamespaceDeclaration( wsu,WSU_NS);

字符串certEncodedID = X509Token,timeStampID = TS,signedBodyID = Body;
//(ii)添加二进制安全令牌。
//< wsse:BinarySecurityToken EncodingType = ...#Base64Binary; ValueType = ...#X509v3 wsu:Id = X509Token> ROS数字证书的base64编码值。
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();
字符串encodeToString = Base64.getEncoder()。encodeToString(certByte);
binarySecurityToken.addTextNode(encodeToString);

//(iii)添加TimeStamp元素-< wsu:Timestamp wsu:Id =" TS>
SOAPElement timestamp = securityElement.addChildElement( Timestamp, wsu);
timestamp.addAttribute(soapEnv.createName( Id, wsu,WSU_NS),timeStampID);
字符串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)添加签名元素
// //< wsse:Security> < ds:Signature> < ds:KeyInfo> < wsse:SecurityTokenReference>
SOAPElement securityTokenReference = securityElement.addChildElement( SecurityTokenReference, wsse);
SOAPElement参考= securityTokenReference.addChildElement( Reference, wsse);
reference.setAttribute( URI,# + certEncodedID); //< wsse:BinarySecurityToken wsu:Id = X509Token;

//< ds:SignedInfo>
字符串providerName = System.getProperty( jsr105Provider, org.jcp.xml.dsig.internal.dom.XMLDSigRI);
XMLSignatureFactory xmlSignatureFactory = XMLSignatureFactory.getInstance( DOM,(提供者)Class.forName(providerName).newInstance());

//摘要方法-< ds:SignatureMethod Algorithm = http://www.w3.org/2000/09/xmldsig#rsa-sha1 />
javax.xml.crypto.dsig.DigestMethod摘要方法= xmlSignatureFactory.newDigestMethod(digestMethodAlog_SHA1,null);

ArrayList< Transform> transformList = new ArrayList< Transform>();
//转换-< ds:Reference URI ='#Body'>
转换envTransform = xmlSignatureFactory.newTransform(transformAlog,(TransformParameterSpec)null);
transformList.add(envTransform);
//参考文献< ds:参考文献URI =#Body>
ArrayList< Reference> refList = new ArrayList< Reference>();
参考refTS = xmlSignatureFactory.newReference(# + timeStampID,digestMethod,transformList,null,null);
参考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 signatureInfo = xmlSignatureFactory.newSignedInfo(cm,sm,refList);

DOMSignContext signContext =新的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 =新的DOMStructure(securityTokenReference);
javax.xml.crypto.dsig.keyinfo.KeyInfo keyInfo = keyFactory.newKeyInfo(java.util.Collections.singletonList(domKeyInfo));
javax.xml.crypto.dsig.XMLSignature签名= xmlSignatureFactory.newXMLSignature(signedInfo,keyInfo);
signContext.setBaseURI();

signature.sign(signContext);
返还肥皂
}

使用证书和私钥 Baeldung.cer,Baeldung.p12 (密码=密码)

  //依赖关系:groupId:xml-security,artifactId:xmlsec,版本:1.3.0 
//依赖关系:groupId:xalan ,artifactId:xalan,版本:2.7.1
公共类SOAP_Security_Signature {
静态最终字符串
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-实用程序-1.0.xsd,
DSIG_NS = http://www.w3.org/2000/09/xmldsig#,// javax.xml.crypto.dsig.XMLSignature.XMLNS,常量。 SignatureSpecNS

binarySecurityToken_Encoding = http://docs.oasis-open.org/wss/2004/01/oasis-200 401-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 ,// 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

静态{
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
}
公共静态X509Certificate loadPublicKeyX509(InputStream cerFileStream)抛出CertificateException,NoSuchProviderException {
CertificateFactory certificateFactory = CertificateFactory.getInstance( X.509, BC);
X509Certificate x509Certificate =(X509Certificate)certificateFactory.generateCertificate(cerFileStream);
return x509Certificate;
}
公共静态私有密钥loadPrivateKeyforSigning(InputStream cerFileStream,字符串密码)抛出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;
字符串别名= null;
if(keyStoreAliasEnum.hasMoreElements()){
alias = keyStoreAliasEnum.nextElement();
if(password!= null){
privateKey =(PrivateKey)keyStore.getKey(alias,password.toCharArray());
}
}
返回privateKey;
}
静态X509证书loadPublicKeyX509;
静态PrivateKey privateKey;
静态字符串路径= C:/ Yash / SOAP /,privateKeyFilePath =路径+ Baeldung.p12,publicKeyFilePath =路径+ Baeldung.cer,
inputFile = path + Soap1.xml,outputFile =路径+ output.xml;
public static void main(String [] args)引发异常{

InputStream pkcs_FileStream = new FileInputStream(privateKeyFilePath);
privateKey = loadPrivateKeyforSigning(pkcs_FileStream, password));
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);

System.out.println( Signature Succesfull.Verify the Signature);
boolean soapXmlWSSEDigitalSignatureValid = isSOAPXmlWSSEDigitalSignatureValid(outputFile,publicKey);
System.out.println( isSOAPXmlDigitalSignatureValid: + soapXmlWSSEDigitalSignatureValid);
}


公共静态无效outputSOAPMessageToFile(SOAPMessage soapMessage)抛出SOAPException,IOException {
File outputFileNew = new File(outputFile);
java.io.FileOutputStream fos = new java.io.FileOutputStream(outputFileNew);
soapMessage.writeTo(fos);
fos.close();
}

公共静态字符串toStringDocument(Document doc)引发TransformerException {
StringWriter sw = new StringWriter();
TransformerFactory tf = TransformerFactory.newInstance();
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();
}
公共静态字符串getFileString(String xmlFilePath)抛出FileNotFoundException {
File file = new File(xmlFilePath);
// FileInputStream parseXMLStream = new FileInputStream(file.getAbsolutePath());

扫描仪扫描仪=新的扫描仪(文件, UTF-8);
字符串xmlContent = Scanner.useDelimiter( \\A)。next();
Scanner.close(); //将此调用放入最后一个块
System.out.println( Str: + xmlContent);
返回xmlContent;
}
公共静态文档getDocument(String xmlData,boolean isXMLData)引发异常{
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
dbFactory.setNamespaceAware(true);
dbFactory.setIgnoringComments(true);
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
文件文件;
if(isXMLData){
InputSource ips = new org.xml.sax.InputSource(new StringReader(xmlData));
doc = dBuilder.parse(ips);
} else {
doc = dBuilder.parse(new File(xmlData));
}
退货单据;
}

private void callTheWebServiceFromFile()引发IOException,SOAPException {
//加载soap请求文件
File soapFile = new File(outputFile);
FileInputStream fis =新的FileInputStream(soapFile);
javax.xml.transform.stream.StreamSource ss = new javax.xml.transform.stream.StreamSource(fis);

//创建SOAP消息对象
SOAPMessage msg = MessageFactory.newInstance()。createMessage();
SOAPPart soapPart = msg.getSOAPPart();

//使用流源
soapPart.setContent(ss)设置soapPart内容;

//创建一个Web服务连接
SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
SOAPConnection soapConnection = soapConnectionFactory.createConnection();

//调用webService。
字符串soapEndpointUrl = https://softwaretest.ros.ie/paye-employers/v1/soap;
SOAPMessage resp = soapConnection.call(msg,soapEndpointUrl);

//读取结果
resp.writeTo(System.out);

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

输入要签名的SOAP XML:


< pre class = lang-xml prettyprint-override> <?xml version = 1.0 encoding = UTF-8 standalone =否?
< env:Envelope xmlns:env =" http://www.w3.org/2003/05/soap-envelope>
< env:Body>
<产品版本= 11.1.2.4.0> <!-数据XML->
< name> API网关< / name>
< company> Oracle< / company>
< description> SOA安全性和管理< / description>
< / product>
< / env:Body>
< / env:Envelope>

WS-Security签名XML:

 <?xml version = 1.0 encoding = UTF-8? 
< env:Envelope
xmlns:env =" http://www.w3.org/2003/05/soap-envelope>
< env: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>
< wsse:BinarySecurityToken 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 WSU:编号= QUOT; X509Token"> MIIDPjCCAiagAwIBAgIJAPvd1gx14C3CMA0GCSqGSIb3DQEBBQUAMEcxCzAJBgNVBAYTAk1BMRAwDgYDVQQIEwdNb3JvY2NvMRMwEQYDVQQHEwpDYXNhYmxhbmNhMREwDwYDVQQDEwhCYWVsZHVuZzAeFw0xNzEwMTIxMDQzMTRaFw0yNzEwMTMxMDQzMTRaMEcxCzAJBgNVBAYTAk1BMRAwDgYDVQQIEwdNb3JvY2NvMRMwEQYDVQQHEwpDYXNhYmxhbmNhMREwDwYDVQQDEwhCYWVsZHVuZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMyi5GmOeN4QaH / CP5gSOyHX8znb5TDHWV8wc + ZT7kNU8zt5tGMhjozK6hax155 / 6tOsBDR0rSYBhL + DM / + uCVS7qOlRHhf6cNGtzGF1gnNJB2WjI8oMAYm24xpLj1WphKUwKrn3nTMPnQup5OoNAMYl99flANrRYVjjxrLQvDZDUio6IujrCZ2TtXGM0g / GP ++ 28KT7g1KlUui3xtB0u33wx7UN8Fix3JmjOaPHGwxGpwP3VGSjfs8cuhqVwRQaZpCOoHU / P8wpXKw80sSdhz + SRueMPtVYqK0CiLL5 / O0h0Y3le4IVwhgg3KG1iTGOWn60UMFn1EYmQ18k5Nsma6UCAwEAAaMtMCswCQYDVR0TBAIwADARBglghkgBhvhCAQEEBAMCBPAwCwYDVR0PBAQDAgUgMA0GCSqGSIb3DQEBBQUAA4IBAQC8DDBmJ3p4xytxBiE0s4p1715WT6Dm / QJHp0XC0hkSoyZKDh + XVmrzm + J3SiW1vpswb5hLgPo040YX9jnDmgOD + TpleTuKHxZRYj92UYWmdjkWLVtFMcvOh + gxBiAPpHIqZsqo8lfcyAuh8Jx834IXbknfCUtERDLG / rU9P / 3XJhrM2GC5qPQznrW4EYhUCGPyIJXm vATMVvXMWCtfogAL + n42vjYXQXZoAWomHhLHoNbSJUErnNdWDOh4WoJtXJCxA6U5LSBplqb3wB2hUTqw + 0admKltvmy + KA1PD7OxoGiY7V544zeGqJy1SV
< wsu:Timestamp wsu:Id = TS>
< wsu:Created> 2020-08-27T12:03:23.288Z< / wsu:Created>
< wsu:Expires> 2020-08-27T12:03:53.293Z< / wsu:Expires>
< / wsu:Timestamp>
< ds:签名
xmlns:ds =" http://www.w3.org/2000/09/xmldsig#">
< ds:SignedInfo>
< ds:CanonicalizationMethod Algorithm = http://www.w3.org/2001/10/xml-exc-c14n# />
< ds:SignatureMethod Algorithm =" http://www.w3.org/2000/09/xmldsig#rsa-sha1>
< ds:参考URI =#Body>
< ds:Transforms>
< ds:Transform Algorithm = http://www.w3.org/2001/10/xml-exc-c14n# />
< / ds:Transforms>
< ds:DigestMethodAlgorithm = http://www.w3.org/2000/09/xmldsig#sha1 />
< ds:DigestValue> RU8XbQ1 / kx / CPZpgxG9fa / lia8Q =< / ds:DigestValue>
< / ds:Reference>
< ds:参考URI =#TS>
< ds:Transforms>
< ds:Transform Algorithm = http://www.w3.org/2001/10/xml-exc-c14n# />
< / ds:Transforms>
< ds:DigestMethodAlgorithm = http://www.w3.org/2000/09/xmldsig#sha1 />
< ds:DigestValue> YZTSgGN / tvrcpeFZ00aWCpVrXZU =< / ds:DigestValue>
< / ds:Reference>
< / ds:SignedInfo>
将DS:SignatureValue所> hgGYDvkc3YPG1ptb6FMnQJV0t1GExjHIOGsXjAwG6uIYLDvkt10ve + AOynBAiSP0CR1NDI6mlXd +
5v5oa2XLEcbuO62v8yj0o1Kr + gkiaf1zo / qZkpwyT5iBkmabNcEzRE8iDCKwTOfFkG4PVRkCOE0D
Q4I84AeYnLAHaoF9IGpbjk0MdXKFIsSTmAmR92BHnjsOyUi1CD6N / 7GDscNLfYoEtMEwovFbupUP
qbJNaq + M / bi5dnTEVqG / TIGftc / me8NVXQiohRq6U8sSAMbLdF5P + iGivcqlLD5xthXfBPHpwruK
euXNan7Jxc9cc5QFx3Rcirvqg / iJ0sPAHRuPGQ ==< / ds:SignatureValue>
< ds:KeyInfo>
< wsse:SecurityTokenReference>
< wsse:Reference URI =#X509Token />
< / wsse:SecurityTokenReference>
< / ds:KeyInfo>
< / ds:Signature>
< / wsse:Security>
< / env:Header>
< env:Body
xmlns:wsu = http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd ; wsu:Id = Body>
<产品版本= 11.1.2.4.0>
< name> API网关< / name>
< company> Oracle< / company>
< description> SOA安全性和管理< / description>
< / product>
< / env:Body>
< / env:Envelope>




用于SOAP XML数字签名 我能够签名并验证


SOAP XML信封签名:

 < s:Envelope xmlns:s =" http://schemas.xmlsoap.org/soap/envelope /> 
< s:Header>
< dsig:Signature xmlns:dsig = http://www.w3.org/2000/09 / ... id = Sample
...
< / dsig:Signature>
< / s:Header>
< s:Body>
...
< / s:Body>
< / s:信封>


解决方案

在您的 isSOAPXmlWSSEDigitalSignatureValid 方法,您需要为每个 Reference d元素显式设置 Id 属性作为元素id属性,则默认情况下不采用它们: https://issues.apache.org/jira/浏览/ SANTUARIO-312

  public static boolean isSOAPXmlWSSEDigitalSignatureValid(StringsignedXmlFilePath,PublicKey publicKey)引发异常{ 
字符串xmlContent = getFileString(signedXmlFilePath);

DocumentsignedDoc = getDocument(xmlContent,true);
signedDoc.createElementNS(DSIG_NS, ds); // qualifiedName = ds;
signedDoc.createElementNS(WSU_NS, wsu);
signedDoc.createElementNS(WSSE_NS, wsse);

//为SOAP正文元素
注册XML ID NodeList soapBodyElements = signedDoc.getElementsByTagNameNS( http://www.w3.org/2003/05/soap-envelope, ; Body);
if(soapBodyElements.getLength()== 0){
抛出new Exception(找不到元素SOAP主体);
}

元素soapBodyElement =(Element)soapBodyElements.item(0);
soapBodyElement.setIdAttributeNS( http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd, Id,true) ;

//为时间戳记元素
注册XML ID NodeList时间戳记= signedDoc.getElementsByTagNameNS( http://docs.oasis-open.org/wss/2004/01/oasis-200401 -wss-wssecurity-utility-1.0.xsd, Timestamp);
if(timestamps.getLength()== 0){
throw new Exception( Element Timestamp not found);
}

Element timestampElement =(Element)timestamps.item(0);
timestampElement.setIdAttributeNS( http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd, Id,true) ;

//加载签名
NodeList signatureNodes = signedDoc.getElementsByTagNameNS(javax.xml.crypto.dsig.XMLSignature.XMLNS, Signature);
if(signatureNodes.getLength()== 0){
抛出新的异常(未找到XML数字签名,文档被丢弃);
}

Element sigElement =(Element)signatureNodes.item(0);
if(sigElement == null)
抛出new Exception( Signature元素为null!);

Init.init();
XMLSignature签名=新的XMLSignature(sigElement,);
return signature.checkSignatureValue(publicKey);
}


I am able to sign the SOAP XML using a certificate for the WS-Security signature. But i am unable to verify its signature. On verifying the signature it leads to Exception, Some help will be appreciated to resolve the issue

SOAP Enveloped WS-Security signature:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
 <s:Header>
  <ws:Security xmlns:ws="http://schemas.xmlsoap.org/..." s:actor="test">
   <dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/..." id="Sample">
       ...
   </dsig:Signature>
  </ws:Security>
 </s:Header>
 <s:Body>
  ...
 </s:Body>
</s:Envelope>

When i try to verify the SOAP XML i am getting the following Exception:

org.apache.xml.security.signature.MissingResourceFailureException: The Reference for URI #Body has no XMLSignatureInput

public static boolean isSOAPXmlWSSEDigitalSignatureValid(String signedXmlFilePath, PublicKey publicKey) throws Exception {
    String xmlContent = getFileString(signedXmlFilePath);
    
    Document signedDoc = getDocument(xmlContent.trim(), true);
    signedDoc.createElementNS(DSIG_NS, "ds"); // qualifiedName = "ds";
    signedDoc.createElementNS(WSU_NS, "wsu");
    signedDoc.createElementNS(WSSE_NS, "wsse");
    
    // load signature
    NodeList signatureNodes = signedDoc.getElementsByTagNameNS(javax.xml.crypto.dsig.XMLSignature.XMLNS, "Signature");
    if (signatureNodes.getLength() == 0) {
        throw new Exception("No XML Digital Signature Found, document is discarded");
    }
    
    Element sigElement = (Element) signatureNodes.item(0);
    if (sigElement == null) 
        throw new Exception("Signature element is null!");
        
    org.apache.xml.security.Init.init();
    org.apache.xml.security.signature.XMLSignature signature = new XMLSignature(sigElement, "");
    return signature.checkSignatureValue(publicKey);
}

By Using the following function i am able to sign the XML

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();
        // SOAPMessage message = MessageFactory.newInstance().createMessage(null, fileInputStream);
        SOAPMessage message = MessageFactory.newInstance("SOAP 1.2 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();
    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", (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;
}

Full Example which uses the Certificate And Private Key Baeldung.cer, Baeldung.p12 (password = "password")

// dependency: groupId:xml-security, artifactId:xmlsec, version:1.3.0
// dependency: groupId:xalan, artifactId:xalan, version:2.7.1
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 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[] args) throws Exception {
        
        InputStream pkcs_FileStream = new FileInputStream(privateKeyFilePath);
        privateKey = loadPrivateKeyforSigning(pkcs_FileStream, "password");
        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);
        
        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() throws IOException, SOAPException {
        //load the soap request file
        File soapFile = new File(outputFile);
        FileInputStream fis = new FileInputStream(soapFile);
        javax.xml.transform.stream.StreamSource ss = new javax.xml.transform.stream.StreamSource(fis);

        // Create a SOAP Message Object
        SOAPMessage msg = MessageFactory.newInstance().createMessage();
        SOAPPart soapPart = msg.getSOAPPart();

        // Set the soapPart Content with the stream source
        soapPart.setContent(ss);

        // Create a webService connection
        SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance();
        SOAPConnection soapConnection = soapConnectionFactory.createConnection();

        // Invoke the webService.
        String soapEndpointUrl = "https://softwaretest.ros.ie/paye-employers/v1/soap";
        SOAPMessage resp = soapConnection.call(msg, soapEndpointUrl);

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

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

Input SOAP XML to Sign:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
    <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>

WS-Security Signed XML:

<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope
    xmlns:env="http://www.w3.org/2003/05/soap-envelope">
    <env: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">
            <wsse:BinarySecurityToken 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" wsu:Id="X509Token">MIIDPjCCAiagAwIBAgIJAPvd1gx14C3CMA0GCSqGSIb3DQEBBQUAMEcxCzAJBgNVBAYTAk1BMRAwDgYDVQQIEwdNb3JvY2NvMRMwEQYDVQQHEwpDYXNhYmxhbmNhMREwDwYDVQQDEwhCYWVsZHVuZzAeFw0xNzEwMTIxMDQzMTRaFw0yNzEwMTMxMDQzMTRaMEcxCzAJBgNVBAYTAk1BMRAwDgYDVQQIEwdNb3JvY2NvMRMwEQYDVQQHEwpDYXNhYmxhbmNhMREwDwYDVQQDEwhCYWVsZHVuZzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMyi5GmOeN4QaH/CP5gSOyHX8znb5TDHWV8wc+ZT7kNU8zt5tGMhjozK6hax155/6tOsBDR0rSYBhL+Dm/+uCVS7qOlRHhf6cNGtzGF1gnNJB2WjI8oMAYm24xpLj1WphKUwKrn3nTMPnQup5OoNAMYl99flANrRYVjjxrLQvDZDUio6IujrCZ2TtXGM0g/gP++28KT7g1KlUui3xtB0u33wx7UN8Fix3JmjOaPHGwxGpwP3VGSjfs8cuhqVwRQaZpCOoHU/P8wpXKw80sSdhz+SRueMPtVYqK0CiLL5/O0h0Y3le4IVwhgg3KG1iTGOWn60UMFn1EYmQ18k5Nsma6UCAwEAAaMtMCswCQYDVR0TBAIwADARBglghkgBhvhCAQEEBAMCBPAwCwYDVR0PBAQDAgUgMA0GCSqGSIb3DQEBBQUAA4IBAQC8DDBmJ3p4xytxBiE0s4p1715WT6Dm/QJHp0XC0hkSoyZKDh+XVmrzm+J3SiW1vpswb5hLgPo040YX9jnDmgOD+TpleTuKHxZRYj92UYWmdjkWLVtFMcvOh+gxBiAPpHIqZsqo8lfcyAuh8Jx834IXbknfCUtERDLG/rU9P/3XJhrM2GC5qPQznrW4EYhUCGPyIJXmvATMVvXMWCtfogAL+n42vjYXQXZoAWomHhLHoNbSJUErnNdWDOh4WoJtXJCxA6U5LSBplqb3wB2hUTqw+0admKltvmy+KA1PD7OxoGiY7V544zeGqJam1qxUia7y5BL6uOa/4ShSV8pcJDYz</wsse:BinarySecurityToken>
            <wsu:Timestamp wsu:Id="TS">
                <wsu:Created>2020-08-27T12:03:23.288Z</wsu:Created>
                <wsu:Expires>2020-08-27T12:03:53.293Z</wsu:Expires>
            </wsu:Timestamp>
            <ds:Signature
                xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
                <ds:SignedInfo>
                    <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
                    <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
                    <ds:Reference URI="#Body">
                        <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>RU8XbQ1/kx/CPZpgxG9fa/lia8Q=</ds:DigestValue>
                    </ds:Reference>
                    <ds:Reference URI="#TS">
                        <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>YZTSgGN/tvrcpeFZ00aWCpVrXZU=</ds:DigestValue>
                    </ds:Reference>
                </ds:SignedInfo>
                <ds:SignatureValue>hgGYDvkc3YPG1ptb6FMnQJV0t1GExjHIOGsXjAwG6uIYLDvkt10ve+AOynBAiSP0CR1NDI6mlXd+
5v5oa2XLEcbuO62v8yj0o1Kr+gkiaf1zo/qZkpwyT5iBkmabNcEzRE8iDCKwTOfFkG4PVRkCOE0D
Q4I84AeYnLAHaoF9IGpbjk0MdXKFIsSTmAmR92BHnjsOyUi1CD6N/7GDscNLfYoEtMEwovFbupUP
qbJNaq+M/bi5dnTEVqG/TIGftc/me8NVXQiohRq6U8sSAMbLdF5P+iGivcqlLD5xthXfBPHpwruK
euXNan7Jxc9cc5QFx3Rcirvqg/iJ0sPAHRuPGQ==</ds:SignatureValue>
                <ds:KeyInfo>
                    <wsse:SecurityTokenReference>
                        <wsse:Reference URI="#X509Token"/>
                    </wsse:SecurityTokenReference>
                </ds:KeyInfo>
            </ds:Signature>
        </wsse:Security>
    </env:Header>
    <env:Body
        xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="Body">
        <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>


For SOAP XML digital signature i am able to sign and verify.

SOAP XML Enveloped Signature:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
 <s:Header>
   <dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/..." id="Sample">
       ...
   </dsig:Signature>
 </s:Header>
 <s:Body>
  ...
 </s:Body>
</s:Envelope>

解决方案

In your isSOAPXmlWSSEDigitalSignatureValid method you need to set explicitly the Id attribute as the element id attribute for every Referenced element, they are not assumed by default: https://issues.apache.org/jira/browse/SANTUARIO-312

  public static boolean isSOAPXmlWSSEDigitalSignatureValid(String signedXmlFilePath, PublicKey publicKey) throws Exception {
    String xmlContent = getFileString(signedXmlFilePath);

    Document signedDoc = getDocument(xmlContent, true);
    signedDoc.createElementNS(DSIG_NS, "ds"); // qualifiedName = "ds";
    signedDoc.createElementNS(WSU_NS, "wsu");
    signedDoc.createElementNS(WSSE_NS, "wsse");

    // Register XML ID for SOAP Body element
    NodeList soapBodyElements = signedDoc.getElementsByTagNameNS("http://www.w3.org/2003/05/soap-envelope", "Body");
    if (soapBodyElements.getLength() == 0) {
      throw new Exception("Element SOAP Body not found");
    }

    Element soapBodyElement = (Element) soapBodyElements.item(0);
    soapBodyElement.setIdAttributeNS("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "Id", true);

    // Register XML ID for Timestamp element
    NodeList timestamps = signedDoc.getElementsByTagNameNS("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "Timestamp");
    if (timestamps.getLength() == 0) {
      throw new Exception("Element Timestamp not found");
    }

    Element timestampElement = (Element) timestamps.item(0);
    timestampElement.setIdAttributeNS("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd", "Id", true);

    // load signature
    NodeList signatureNodes = signedDoc.getElementsByTagNameNS(javax.xml.crypto.dsig.XMLSignature.XMLNS, "Signature");
    if (signatureNodes.getLength() == 0) {
      throw new Exception("No XML Digital Signature Found, document is discarded");
    }

    Element sigElement = (Element) signatureNodes.item(0);
    if (sigElement == null)
      throw new Exception("Signature element is null!");

    Init.init();
    XMLSignature signature = new XMLSignature(sigElement, "");
    return signature.checkSignatureValue(publicKey);
  }

这篇关于SOAP XML WS-Security签名验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆