This is an automated email from the ASF dual-hosted git repository.
coheigea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ws-wss4j.git
The following commit(s) were added to refs/heads/master by this push:
new 291c7238e StAX SAML subject confirmation skipped for an empty SOAP
Body (#724)
291c7238e is described below
commit 291c7238e062d04cc42188ca831d0f246a2f0ab1
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Mon Sep 21 15:42:33 2026 +0100
StAX SAML subject confirmation skipped for an empty SOAP Body (#724)
---
.../processor/input/SAMLTokenInputHandler.java | 12 +++++
.../stax/test/saml/SAMLTokenNegativeTest.java | 55 ++++++++++++++++++++++
.../resources/testdata/empty-body-soap-1.1.xml | 4 ++
3 files changed, 71 insertions(+)
diff --git
a/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/SAMLTokenInputHandler.java
b/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/SAMLTokenInputHandler.java
index c47c247f3..71a073cbe 100644
---
a/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/SAMLTokenInputHandler.java
+++
b/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/SAMLTokenInputHandler.java
@@ -69,6 +69,7 @@ import org.apache.xml.security.stax.ext.InputProcessorChain;
import org.apache.xml.security.stax.ext.XMLSecurityConstants;
import org.apache.xml.security.stax.ext.XMLSecurityProperties;
import org.apache.xml.security.stax.ext.stax.XMLSecAttribute;
+import org.apache.xml.security.stax.ext.stax.XMLSecEndElement;
import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
import org.apache.xml.security.stax.ext.stax.XMLSecNamespace;
import org.apache.xml.security.stax.ext.stax.XMLSecStartElement;
@@ -602,6 +603,17 @@ public class SAMLTokenInputHandler extends
AbstractInputSecurityHeaderHandler {
inputProcessorChain.removeProcessor(this);
checkPossessionOfKey(inputProcessorChain,
samlAssertionWrapper, subjectSecurityToken);
}
+ } else if (xmlSecEvent.getEventType() ==
XMLStreamConstants.END_ELEMENT) {
+ // A Body with no element child of its own never produces the
event above, so
+ // without this the subject confirmation of the assertion
would go unchecked for
+ // such a message. The Body end element is the last point at
which the check can
+ // still be made, and every Signature covering the Body has
been seen by then.
+ XMLSecEndElement xmlSecEndElement = xmlSecEvent.asEndElement();
+ List<QName> elementPath = xmlSecEndElement.getElementPath();
+ if (elementPath.size() == 2 &&
WSSUtils.isInSOAPBody(elementPath)) {
+ inputProcessorChain.removeProcessor(this);
+ checkPossessionOfKey(inputProcessorChain,
samlAssertionWrapper, subjectSecurityToken);
+ }
}
return xmlSecEvent;
}
diff --git
a/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/saml/SAMLTokenNegativeTest.java
b/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/saml/SAMLTokenNegativeTest.java
index 4830a0945..6a2ae5682 100755
---
a/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/saml/SAMLTokenNegativeTest.java
+++
b/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/saml/SAMLTokenNegativeTest.java
@@ -233,6 +233,61 @@ public class SAMLTokenNegativeTest extends
AbstractTestBase {
}
}
+ /**
+ * The proof-of-possession check for a holder-of-key assertion used to be
triggered by the
+ * first element inside the SOAP Body. A Body with no element child of its
own produces no
+ * such event, so the check never ran and an assertion whose subject key
the sender does not
+ * hold was accepted.
+ */
+ @Test
+ public void testHOKEmptyBodyInbound() throws Exception {
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ {
+ SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler();
+ callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN);
+
callbackHandler.setConfirmationMethod(SAML1Constants.CONF_HOLDER_KEY);
+ callbackHandler.setIssuer("www.example.com");
+ // The assertion itself is signed, so it gets past the subject
confirmation method
+ // check; what it does not carry is any proof that the sender
holds the subject key.
+ callbackHandler.setSignAssertion(true);
+
+ InputStream sourceDocument =
+
this.getClass().getClassLoader().getResourceAsStream("testdata/empty-body-soap-1.1.xml");
+ String action = WSHandlerConstants.SAML_TOKEN_UNSIGNED;
+ Properties properties = new Properties();
+ properties.put(WSHandlerConstants.SAML_CALLBACK_REF,
callbackHandler);
+ Document securedDocument =
doOutboundSecurityWithWSS4J(sourceDocument, action, properties);
+
+ // The Body must have stayed empty, or the test is not exercising
what it claims to
+ NodeList bodies =
+ securedDocument.getElementsByTagNameNS(
+ "http://schemas.xmlsoap.org/soap/envelope/", "Body");
+ assertEquals(1, bodies.getLength());
+ assertEquals(0,
((Element)bodies.item(0)).getElementsByTagName("*").getLength());
+
+ javax.xml.transform.Transformer transformer =
TRANSFORMER_FACTORY.newTransformer();
+ transformer.transform(new DOMSource(securedDocument), new
StreamResult(baos));
+ }
+
+ {
+ WSSSecurityProperties securityProperties = new
WSSSecurityProperties();
+ securityProperties.loadSignatureVerificationKeystore(
+
this.getClass().getClassLoader().getResource("saml/issuer.jks"),
"default".toCharArray());
+ InboundWSSec wsSecIn = WSSec.getInboundWSSec(securityProperties,
false, true);
+ XMLStreamReader xmlStreamReader =
+ wsSecIn.processInMessage(
+ xmlInputFactory.createXMLStreamReader(new
ByteArrayInputStream(baos.toByteArray())));
+
+ try {
+ StAX2DOM.readDoc(documentBuilderFactory.newDocumentBuilder(),
xmlStreamReader);
+ fail("XMLStreamException expected");
+ } catch (XMLStreamException e) {
+ assertNotNull(e.getCause());
+ }
+ }
+ }
+
@Test
public void testSAML2TrustFailureInbound() throws Exception {
diff --git
a/ws-security-stax/src/test/resources/testdata/empty-body-soap-1.1.xml
b/ws-security-stax/src/test/resources/testdata/empty-body-soap-1.1.xml
new file mode 100644
index 000000000..9b9596b28
--- /dev/null
+++ b/ws-security-stax/src/test/resources/testdata/empty-body-soap-1.1.xml
@@ -0,0 +1,4 @@
+<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
+ <env:Header/>
+ <env:Body/>
+</env:Envelope>