英文:
SOAP XML WS-Security signature verification
问题
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 an 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
Java code to verify the signature:
public static boolean isSOAPXmlWSSEDigitalSignatureValid(String signedXmlFilePath, PublicKey publicKey) throws Exception {
String xmlContent = getFileString(signedXmlFilePath);
Document signedDoc = getDocument(xmlContent.trim(), true);
// ...
// (remaining code is not shown due to length constraints)
// ...
return signature.checkSignatureValue(publicKey);
}
Java code to sign the XML:
public static SOAPMessage WS_Security_signature(String inputFile, boolean isDataXML) throws Exception {
// ...
// (code to create SOAPMessage and add elements)
// ...
SOAPElement securityElement = soapHeader.addChildElement("Security", "wsse", WSSE_NS);
// ...
// (code to add BinarySecurityToken, Timestamp, Signature)
// ...
signature.sign(signContext);
return soapMsg;
}
Full example code and usage are provided as well, but due to the character limit, I'm not able to display the complete content. If you have specific questions or need assistance with parts of the code, feel free to ask.
英文:
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>
答案1
得分: 0
在您的 isSOAPXmlWSSEDigitalSignatureValid
方法中,您需要为每个 Reference
元素显式设置 Id
属性作为元素的 id 属性,而这些属性不会默认被假定: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");
// 为 SOAP Body 元素注册 XML ID
NodeList soapBodyElements = signedDoc.getElementsByTagNameNS("http://www.w3.org/2003/05/soap-envelope", "Body");
if (soapBodyElements.getLength() == 0) {
throw new Exception("找不到 SOAP Body 元素");
}
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);
// 为 Timestamp 元素注册 XML ID
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("找不到 Timestamp 元素");
}
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) {
throw new Exception("未找到 XML 数字签名,文档已被丢弃");
}
Element sigElement = (Element) signatureNodes.item(0);
if (sigElement == null)
throw new Exception("签名元素为空!");
Init.init();
XMLSignature signature = new XMLSignature(sigElement, "");
return signature.checkSignatureValue(publicKey);
}
英文:
In your isSOAPXmlWSSEDigitalSignatureValid
method you need to set explicitly the Id
attribute as the element id attribute for every Reference
d 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);
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论