This is an automated email from the ASF dual-hosted git repository.
coheigea pushed a commit to branch 2_4_x-fixes
in repository https://gitbox.apache.org/repos/asf/ws-wss4j.git
The following commit(s) were added to refs/heads/2_4_x-fixes by this push:
new 6bef3423c Fix timestamp parsing (#722)
6bef3423c is described below
commit 6bef3423c61ff42ff356f52b84218283ac7d02c8
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Mon Sep 21 12:52:49 2026 +0100
Fix timestamp parsing (#722)
---
.../apache/wss4j/dom/message/token/Timestamp.java | 22 +++++++-
.../apache/wss4j/dom/message/TimestampTest.java | 65 ++++++++++++++++++++++
2 files changed, 84 insertions(+), 3 deletions(-)
diff --git
a/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/token/Timestamp.java
b/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/token/Timestamp.java
index e99153cdf..76b1a7ff9 100644
---
a/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/token/Timestamp.java
+++
b/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/token/Timestamp.java
@@ -38,7 +38,6 @@ import org.apache.wss4j.dom.WSConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
-import org.w3c.dom.Text;
/**
* Timestamp according to SOAP Message Security 1.0,
@@ -79,7 +78,7 @@ public class Timestamp {
// We can't have a ValueType attribute as per the
BSP spec
bspEnforcer.handleBSPRule(BSPRule.R3225);
}
- createdString =
((Text)currentChildElement.getFirstChild()).getData();
+ createdString = getRequiredText(currentChildElement);
} else {
// Test for multiple Created elements
bspEnforcer.handleBSPRule(BSPRule.R3203);
@@ -99,7 +98,7 @@ public class Timestamp {
// We can't have a ValueType attribute as per the
BSP spec
bspEnforcer.handleBSPRule(BSPRule.R3226);
}
- strExpires =
((Text)currentChildElement.getFirstChild()).getData();
+ strExpires = getRequiredText(currentChildElement);
}
} else {
bspEnforcer.handleBSPRule(BSPRule.R3222);
@@ -155,6 +154,23 @@ public class Timestamp {
}
+ /**
+ * Return the text content of a Created / Expires element. The element's
first child is not
+ * necessarily a Text node - it may be absent, or be a comment - and
reading it as one turned
+ * wire-supplied content into an unchecked exception rather than an
INVALID_SECURITY fault.
+ */
+ private static String getRequiredText(Element element) throws
WSSecurityException {
+ String text = XMLUtils.getElementText(element);
+ if (text == null) {
+ throw new WSSecurityException(
+ WSSecurityException.ErrorCode.INVALID_SECURITY,
+ "invalidTimestamp",
+ new Object[] {"The " + element.getLocalName() + " element has
no text content"}
+ );
+ }
+ return text;
+ }
+
/**
* Constructs a <code>Timestamp</code> object according
* to the defined parameters.
diff --git
a/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/TimestampTest.java
b/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/TimestampTest.java
index 1994b2778..09a5adda2 100644
---
a/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/TimestampTest.java
+++
b/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/TimestampTest.java
@@ -459,6 +459,71 @@ public class TimestampTest {
verify(doc, Collections.singletonList(BSPRule.R3203));
}
+ /**
+ * A "Created" element with no text content of its own must be rejected as
an invalid
+ * Timestamp, not read as though its first child were a Text node.
+ */
+ @Test
+ public void testEmptyCreated() throws Exception {
+ Document doc = createTimestampWithCreatedContent(null);
+
+ try {
+ verify(doc);
+ fail("The timestamp validation should have failed on an empty
Created element");
+ } catch (WSSecurityException ex) {
+ assertTrue(ex.getErrorCode() ==
WSSecurityException.ErrorCode.INVALID_SECURITY);
+ }
+ }
+
+ /**
+ * The first child of a "Created" element need not be a Text node - here
it is a comment,
+ * which c14n excludes from the signed bytes in any case.
+ */
+ @Test
+ public void testCreatedWithLeadingComment() throws Exception {
+ ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
+ Document doc =
+
createTimestampWithCreatedContent(DateUtil.getDateTimeFormatter(true).format(now),
true);
+
+ verify(doc);
+ }
+
+ private Document createTimestampWithCreatedContent(String createdText)
throws Exception {
+ return createTimestampWithCreatedContent(createdText, false);
+ }
+
+ private Document createTimestampWithCreatedContent(
+ String createdText, boolean leadingComment
+ ) throws Exception {
+ Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
+ WSSecHeader secHeader = new WSSecHeader(doc);
+ secHeader.insertSecurityHeader();
+
+ Element timestampElement =
+ doc.createElementNS(
+ WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" +
WSConstants.TIMESTAMP_TOKEN_LN
+ );
+
+ Element elementCreated =
+ doc.createElementNS(
+ WSConstants.WSU_NS, WSConstants.WSU_PREFIX + ":" +
WSConstants.CREATED_LN
+ );
+ if (leadingComment) {
+ elementCreated.appendChild(doc.createComment("a comment"));
+ }
+ if (createdText != null) {
+ elementCreated.appendChild(doc.createTextNode(createdText));
+ }
+ timestampElement.appendChild(elementCreated);
+
+ secHeader.getSecurityHeaderElement().appendChild(timestampElement);
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug(XMLUtils.prettyDocumentToString(doc));
+ }
+ return doc;
+ }
+
/**
* This is a test for processing an Timestamp where it contains no
"Created" element.
* This Timestamp should be rejected.