SANTUARIO-468 - How to add generated signature element deep inside desired tag in XML through stax implementation. Thanks to Manjesh Kumar for the initial patch.
git-svn-id: https://svn.apache.org/repos/asf/santuario/xml-security-java/trunk@1817215 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/java/org/apache/xml/security/stax/ext/XMLSecurityProperties.java b/src/main/java/org/apache/xml/security/stax/ext/XMLSecurityProperties.java
index a191c99..6ba3c2f 100644
--- a/src/main/java/org/apache/xml/security/stax/ext/XMLSecurityProperties.java
+++ b/src/main/java/org/apache/xml/security/stax/ext/XMLSecurityProperties.java
@@ -76,6 +76,9 @@
private boolean signatureGenerateIds = true;
private boolean signatureIncludeDigestTransform = true;
+ private QName signaturePositionQName;
+ private boolean signaturePositionStart = false;
+
public XMLSecurityProperties() {
}
@@ -112,6 +115,16 @@
this.keyNameMap.putAll(xmlSecurityProperties.keyNameMap);
this.signatureGenerateIds = xmlSecurityProperties.signatureGenerateIds;
this.signatureIncludeDigestTransform = xmlSecurityProperties.signatureIncludeDigestTransform;
+ this.signaturePositionQName = xmlSecurityProperties.signaturePositionQName;
+ this.signaturePositionStart = xmlSecurityProperties.signaturePositionStart;
+ }
+
+ public boolean isSignaturePositionStart() {
+ return signaturePositionStart;
+ }
+
+ public void setSignaturePositionStart(boolean signaturePositionStart) {
+ this.signaturePositionStart = signaturePositionStart;
}
public SecurityTokenConstants.KeyIdentifier getSignatureKeyIdentifier() {
@@ -493,4 +506,12 @@
public void setSignatureIncludeDigestTransform(boolean signatureIncludeDigestTransform) {
this.signatureIncludeDigestTransform = signatureIncludeDigestTransform;
}
+
+ public QName getSignaturePositionQName() {
+ return signaturePositionQName;
+ }
+
+ public void setSignaturePositionQName(QName signaturePositionQName) {
+ this.signaturePositionQName = signaturePositionQName;
+ }
}
diff --git a/src/main/java/org/apache/xml/security/stax/impl/processor/output/XMLSignatureEndingOutputProcessor.java b/src/main/java/org/apache/xml/security/stax/impl/processor/output/XMLSignatureEndingOutputProcessor.java
index 1e3f9ff..9da34c6 100644
--- a/src/main/java/org/apache/xml/security/stax/impl/processor/output/XMLSignatureEndingOutputProcessor.java
+++ b/src/main/java/org/apache/xml/security/stax/impl/processor/output/XMLSignatureEndingOutputProcessor.java
@@ -23,6 +23,7 @@
import java.util.Deque;
import java.util.List;
+import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import org.apache.xml.security.exceptions.XMLSecurityException;
@@ -78,15 +79,6 @@
OutputProcessorChain outputProcessorChain, Deque<XMLSecEvent> xmlSecEventDeque)
throws XMLStreamException, XMLSecurityException {
- // @see SANTUARIO-405
- // Enhances SANTUARIO-324
- // Output the signature at a specific position.
- // By default, this is just after the root element
- int signaturePosition = getSecurityProperties().getSignaturePosition();
- if (signaturePosition < 0) {
- signaturePosition = 0;
- }
-
// forward to the root element and output it
XMLSecEvent xmlSecEvent = xmlSecEventDeque.pop();
while (!xmlSecEvent.isStartElement()) {
@@ -99,25 +91,57 @@
// search the specified position
int depth = 0;
- int position = 0;
- while (position != signaturePosition) {
- xmlSecEvent = xmlSecEventDeque.pop();
+ QName signaturePositionQName = getSecurityProperties().getSignaturePositionQName();
+ boolean start = getSecurityProperties().isSignaturePositionStart();
+ if (signaturePositionQName != null) {
+ while (!xmlSecEventDeque.isEmpty()
+ && !(start && xmlSecEvent.isStartElement() && xmlSecEvent.asStartElement().getName().equals(signaturePositionQName)
+ || !start && xmlSecEvent.isEndElement() && xmlSecEvent.asEndElement().getName().equals(signaturePositionQName))) {
+ xmlSecEvent = xmlSecEventDeque.pop();
- if (xmlSecEvent.isStartElement()) {
- depth++;
- } else if (xmlSecEvent.isEndElement()) {
- depth--;
- if (depth == 0) {
- position++;
- } else if (depth < 0) {
- // root-end-element reached
- xmlSecEventDeque.push(xmlSecEvent);
- break;
+ if (xmlSecEvent.isStartElement()) {
+ depth++;
+ } else if (xmlSecEvent.isEndElement()) {
+ depth--;
+ if (depth < 0) {
+ // root-end-element reached
+ xmlSecEventDeque.push(xmlSecEvent);
+ break;
+ }
}
- }
- outputProcessorChain.reset();
- outputProcessorChain.processEvent(xmlSecEvent);
+ outputProcessorChain.reset();
+ outputProcessorChain.processEvent(xmlSecEvent);
+ }
+ } else {
+ // @see SANTUARIO-405
+ // Enhances SANTUARIO-324
+ // Output the signature at a specific position.
+ // By default, this is just after the root element
+ int signaturePosition = getSecurityProperties().getSignaturePosition();
+ if (signaturePosition < 0) {
+ signaturePosition = 0;
+ }
+ int position = 0;
+ while (position != signaturePosition) {
+ xmlSecEvent = xmlSecEventDeque.pop();
+
+ if (xmlSecEvent.isStartElement()) {
+ depth++;
+ } else if (xmlSecEvent.isEndElement()) {
+ depth--;
+ if (depth == 0) {
+ position++;
+ } else if (depth < 0) {
+ // root-end-element reached
+ xmlSecEventDeque.push(xmlSecEvent);
+ break;
+ }
+ }
+
+ outputProcessorChain.reset();
+ outputProcessorChain.processEvent(xmlSecEvent);
+ }
}
//...then call super to append the signature and flush the rest
diff --git a/src/test/java/org/apache/xml/security/test/stax/signature/SignatureCreationTest.java b/src/test/java/org/apache/xml/security/test/stax/signature/SignatureCreationTest.java
index a33ba56..d117ccc 100644
--- a/src/test/java/org/apache/xml/security/test/stax/signature/SignatureCreationTest.java
+++ b/src/test/java/org/apache/xml/security/test/stax/signature/SignatureCreationTest.java
@@ -296,7 +296,20 @@
signAtSpecificPosition(999);
}
+ @Test
+ public void testSignAtSpecificPositionViaQName() throws Exception {
+ signAtSpecificPosition(0, new QName("urn:example:po", "PurchaseOrder"), true);
+ signAtSpecificPosition(0, new QName("urn:example:po", "Items"), true);
+ signAtSpecificPosition(0, new QName("urn:example:po", "Items"), false);
+ signAtSpecificPosition(0, new QName("urn:example:po", "ShippingAddress"), true);
+ signAtSpecificPosition(0, new QName("urn:example:po", "ShippingAddress"), false);
+ }
+
private void signAtSpecificPosition(int position) throws Exception {
+ signAtSpecificPosition(position, null, false);
+ }
+
+ private void signAtSpecificPosition(int position, QName positionQName, boolean start) throws Exception {
// Set up the Configuration
XMLSecurityProperties properties = new XMLSecurityProperties();
List<XMLSecurityConstants.Action> actions = new ArrayList<XMLSecurityConstants.Action>();
@@ -305,6 +318,8 @@
// Specify the signature position
properties.setSignaturePosition(position);
+ properties.setSignaturePositionQName(positionQName);
+ properties.setSignaturePositionStart(start);
// Set the key up
KeyStore keyStore = KeyStore.getInstance("jks");
@@ -340,7 +355,7 @@
XmlReaderToWriter.writeAll(xmlStreamReader, xmlStreamWriter);
xmlStreamWriter.close();
- //System.out.println("Got:\n" + new String(baos.toByteArray(), StandardCharsets.UTF_8.name()));
+ // System.out.println("Got:\n" + new String(baos.toByteArray(), StandardCharsets.UTF_8.name()));
Document document = null;
try (InputStream is = new ByteArrayInputStream(baos.toByteArray())) {
@@ -350,15 +365,32 @@
//find first child element:
Node childNode = XMLUtils.getNextElement(document.getDocumentElement().getFirstChild());
- int expectedPosition = position < 0 ? 0 : position;
- int curPos = 0;
- while (curPos != expectedPosition) {
- Node node = XMLUtils.getNextElement(childNode.getNextSibling());
- curPos++;
- if (node != null) {
- childNode = node;
- } else {
- break;
+ if (positionQName != null) {
+ // Find the Signature node inside the desired QName
+ String localName = positionQName.getLocalPart();
+ if (!"PurchaseOrder".equals(localName)) {
+ String namespace = positionQName.getNamespaceURI();
+ while (childNode != null && !(childNode.getLocalName().equals(localName)
+ && childNode.getNamespaceURI().equals(namespace))) {
+ childNode = XMLUtils.getNextElement(childNode.getNextSibling());
+ }
+ if (start) {
+ childNode = childNode.getFirstChild();
+ } else {
+ childNode = childNode.getNextSibling();
+ }
+ }
+ } else {
+ int expectedPosition = position < 0 ? 0 : position;
+ int curPos = 0;
+ while (curPos != expectedPosition) {
+ Node node = XMLUtils.getNextElement(childNode.getNextSibling());
+ curPos++;
+ if (node != null) {
+ childNode = node;
+ } else {
+ break;
+ }
}
}