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 ef2bb58a7 Fix issues with SignedElements / EncryptedElements (#682)
ef2bb58a7 is described below

commit ef2bb58a7fda08612cd94dc6d5e1464f2995dd0e
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Wed Sep 9 14:18:33 2026 +0100

    Fix issues with SignedElements / EncryptedElements (#682)
---
 .../org/apache/wss4j/policy/stax/PolicyUtils.java  | 111 +++++++++++++++++++--
 .../ContentEncryptedElementsAssertionState.java    |  14 ++-
 .../EncryptedElementsAssertionState.java           |  14 ++-
 .../RequiredElementsAssertionState.java            |  22 ++--
 .../SignedElementsAssertionState.java              |  14 +--
 .../test/AsymmetricBindingIntegrationTest.java     |  18 ----
 .../wss4j/policy/stax/test/SignedElementsTest.java |  49 +++++++++
 7 files changed, 183 insertions(+), 59 deletions(-)

diff --git 
a/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/PolicyUtils.java
 
b/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/PolicyUtils.java
index 16de0768e..6aa5309b7 100644
--- 
a/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/PolicyUtils.java
+++ 
b/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/PolicyUtils.java
@@ -18,37 +18,134 @@
  */
 package org.apache.wss4j.policy.stax;
 
+import org.apache.wss4j.common.WSSPolicyException;
 import org.apache.wss4j.policy.model.XPath;
+import org.apache.wss4j.stax.utils.WSSUtils;
 
 import javax.xml.namespace.QName;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.regex.Pattern;
 
 public final class PolicyUtils {
 
+    // Conservative approximation of an XML NCName; rejects wildcards ("*"), 
predicates
+    // (e.g. "Body[1]") and functions, which getElementPath cannot represent 
as a QName step.
+    private static final Pattern NCNAME_PATTERN = 
Pattern.compile("^[A-Za-z_][\\w.-]*$");
+
     private PolicyUtils() {
         // complete
     }
 
+    /**
+     * Parses an XPath into raw QName steps.
+     */
     public static List<QName> getElementPath(XPath xPath) {
+        try {
+            return getElementPathDescriptor(xPath).getPath();
+        } catch (WSSPolicyException e) {
+            throw new IllegalArgumentException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Parses a sp:XPath expression into validated element steps. Only chains 
of plain
+     * prefix:localName (or localName) steps are supported, either absolute 
(leading "/") or
+     * relative; wildcards, predicates, functions and descendant ("//") steps 
are rejected
+     * instead of silently producing a path that could never match a real 
element (CWE-347).
+     */
+    public static ElementPath getElementPathDescriptor(XPath xPath) throws 
WSSPolicyException {
+        String xPathString = xPath.getXPath();
+        if (xPathString == null || xPathString.isEmpty()) {
+            throw new WSSPolicyException("Empty XPath expression");
+        }
+        boolean absolute = xPathString.charAt(0) == '/';
+
         List<QName> elements = new ArrayList<>();
-        String[] xPathElements = xPath.getXPath().split("/");
+        String[] xPathElements = xPathString.split("/");
         for (int j = 0; j < xPathElements.length; j++) {
             String xPathElement = xPathElements[j];
-            if (xPathElement == null || xPathElement.length() == 0) {
-                continue;
+            if (xPathElement.isEmpty()) {
+                // only the leading '/' of an absolute path may produce an 
empty step;
+                // any other empty step means a "//" descendant axis, which 
isn't supported
+                if (absolute && j == 0) {
+                    continue;
+                }
+                throw new WSSPolicyException(
+                    "Unsupported XPath expression, descendant ('//') steps are 
not supported: " + xPathString);
             }
             String[] elementParts = xPathElement.split(":");
-            if (elementParts.length == 2) {
+            if (elementParts.length == 2 && isNCName(elementParts[0]) && 
isNCName(elementParts[1])) {
                 String ns = xPath.getPrefixNamespaceMap().get(elementParts[0]);
                 if (ns == null) {
-                    throw new IllegalArgumentException("Namespace not 
declared");
+                    throw new WSSPolicyException("Namespace not declared for 
prefix: " + elementParts[0]);
                 }
                 elements.add(new QName(ns, elementParts[1]));
-            } else {
+            } else if (elementParts.length == 1 && isNCName(elementParts[0])) {
                 elements.add(new QName(elementParts[0]));
+            } else {
+                throw new WSSPolicyException(
+                    "Unsupported XPath step (wildcards, predicates and 
functions are not supported): "
+                        + xPathElement);
             }
         }
-        return elements;
+        return new ElementPath(elements, absolute);
+    }
+
+    private static boolean isNCName(String name) {
+        return NCNAME_PATTERN.matcher(name).matches();
+    }
+
+    /**
+     * Wraps an already fully-qualified, absolute element path (e.g. a 
well-known SOAP header
+     * path built in code) as an ElementPath that must match the observed path 
exactly.
+     */
+    public static ElementPath absoluteElementPath(List<QName> path) {
+        return new ElementPath(path, true);
+    }
+
+    /**
+     * The element steps parsed from a sp:XPath expression. An absolute path 
must match the
+     * observed element path exactly; a relative path must match its trailing 
steps (tail).
+     */
+    public static final class ElementPath {
+        private final List<QName> path;
+        private final boolean absolute;
+
+        private ElementPath(List<QName> path, boolean absolute) {
+            this.path = path;
+            this.absolute = absolute;
+        }
+
+        public List<QName> getPath() {
+            return path;
+        }
+
+        public boolean matches(List<QName> observedPath) {
+            if (absolute) {
+                return WSSUtils.pathMatches(path, observedPath);
+            }
+            if (observedPath == null || observedPath.size() < path.size()) {
+                return false;
+            }
+            return WSSUtils.pathMatches(path, 
observedPath.subList(observedPath.size() - path.size(), observedPath.size()));
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (this == o) {
+                return true;
+            }
+            if (!(o instanceof ElementPath)) {
+                return false;
+            }
+            ElementPath other = (ElementPath) o;
+            return absolute == other.absolute && path.equals(other.path);
+        }
+
+        @Override
+        public int hashCode() {
+            return path.hashCode() * 31 + (absolute ? 1 : 0);
+        }
     }
 }
diff --git 
a/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/ContentEncryptedElementsAssertionState.java
 
b/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/ContentEncryptedElementsAssertionState.java
index 3e00acd31..f8634729d 100644
--- 
a/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/ContentEncryptedElementsAssertionState.java
+++ 
b/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/ContentEncryptedElementsAssertionState.java
@@ -33,8 +33,6 @@ import org.apache.wss4j.policy.stax.PolicyUtils;
 import org.apache.wss4j.stax.securityEvent.WSSecurityEventConstants;
 import org.apache.wss4j.stax.utils.WSSUtils;
 
-import javax.xml.namespace.QName;
-
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -44,18 +42,18 @@ import java.util.List;
  */
 public class ContentEncryptedElementsAssertionState extends AssertionState 
implements Assertable {
 
-    private final List<List<QName>> pathElements = new ArrayList<>();
+    private final List<PolicyUtils.ElementPath> pathElements = new 
ArrayList<>();
     private PolicyAsserter policyAsserter;
 
     public ContentEncryptedElementsAssertionState(AbstractSecurityAssertion 
assertion,
                                                   PolicyAsserter 
policyAsserter,
-                                                  boolean asserted) {
+                                                  boolean asserted) throws 
WSSPolicyException {
         super(assertion, asserted);
 
         ContentEncryptedElements contentEncryptedElements = 
(ContentEncryptedElements) assertion;
         for (int i = 0; i < contentEncryptedElements.getXPaths().size(); i++) {
             XPath xPath = contentEncryptedElements.getXPaths().get(i);
-            List<QName> elements = PolicyUtils.getElementPath(xPath);
+            PolicyUtils.ElementPath elements = 
PolicyUtils.getElementPathDescriptor(xPath);
             pathElements.add(elements);
         }
 
@@ -80,10 +78,10 @@ public class ContentEncryptedElementsAssertionState extends 
AssertionState imple
     public boolean assertEvent(SecurityEvent securityEvent) throws 
WSSPolicyException {
         ContentEncryptedElementSecurityEvent 
contentEncryptedElementSecurityEvent = (ContentEncryptedElementSecurityEvent) 
securityEvent;
 
-        Iterator<List<QName>> pathElementIterator = pathElements.iterator();
+        Iterator<PolicyUtils.ElementPath> pathElementIterator = 
pathElements.iterator();
         while (pathElementIterator.hasNext()) {
-            List<QName> pathElements = pathElementIterator.next();
-            if (WSSUtils.pathMatches(pathElements, 
contentEncryptedElementSecurityEvent.getElementPath())) {
+            PolicyUtils.ElementPath pathElement = pathElementIterator.next();
+            if 
(pathElement.matches(contentEncryptedElementSecurityEvent.getElementPath())) {
                 if (contentEncryptedElementSecurityEvent.isEncrypted()) {
                     setAsserted(true);
                     policyAsserter.assertPolicy(getAssertion());
diff --git 
a/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/EncryptedElementsAssertionState.java
 
b/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/EncryptedElementsAssertionState.java
index 535e39123..bcd264cb1 100644
--- 
a/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/EncryptedElementsAssertionState.java
+++ 
b/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/EncryptedElementsAssertionState.java
@@ -33,8 +33,6 @@ import org.apache.wss4j.policy.stax.PolicyUtils;
 import org.apache.wss4j.stax.securityEvent.WSSecurityEventConstants;
 import org.apache.wss4j.stax.utils.WSSUtils;
 
-import javax.xml.namespace.QName;
-
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
@@ -44,18 +42,18 @@ import java.util.List;
  */
 public class EncryptedElementsAssertionState extends AssertionState implements 
Assertable {
 
-    private final List<List<QName>> pathElements = new ArrayList<>();
+    private final List<PolicyUtils.ElementPath> pathElements = new 
ArrayList<>();
     private PolicyAsserter policyAsserter;
 
     public EncryptedElementsAssertionState(AbstractSecurityAssertion assertion,
                                            PolicyAsserter policyAsserter,
-                                           boolean asserted) {
+                                           boolean asserted) throws 
WSSPolicyException {
         super(assertion, asserted);
 
         EncryptedElements encryptedElements = (EncryptedElements) assertion;
         for (int i = 0; i < encryptedElements.getXPaths().size(); i++) {
             XPath xPath = encryptedElements.getXPaths().get(i);
-            List<QName> elements = PolicyUtils.getElementPath(xPath);
+            PolicyUtils.ElementPath elements = 
PolicyUtils.getElementPathDescriptor(xPath);
             pathElements.add(elements);
         }
 
@@ -82,10 +80,10 @@ public class EncryptedElementsAssertionState extends 
AssertionState implements A
         AbstractSecuredElementSecurityEvent encryptedElementSecurityEvent =
             (AbstractSecuredElementSecurityEvent) securityEvent;
 
-        Iterator<List<QName>> pathElementIterator = pathElements.iterator();
+        Iterator<PolicyUtils.ElementPath> pathElementIterator = 
pathElements.iterator();
         while (pathElementIterator.hasNext()) {
-            List<QName> pathElements = pathElementIterator.next();
-            if (WSSUtils.pathMatches(pathElements, 
encryptedElementSecurityEvent.getElementPath())) {
+            PolicyUtils.ElementPath pathElement = pathElementIterator.next();
+            if 
(pathElement.matches(encryptedElementSecurityEvent.getElementPath())) {
                 if (encryptedElementSecurityEvent.isEncrypted()) {
                     setAsserted(true);
                     policyAsserter.assertPolicy(getAssertion());
diff --git 
a/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/RequiredElementsAssertionState.java
 
b/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/RequiredElementsAssertionState.java
index ce91e1087..d4eae6b73 100644
--- 
a/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/RequiredElementsAssertionState.java
+++ 
b/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/RequiredElementsAssertionState.java
@@ -45,19 +45,19 @@ import java.util.Map;
  */
 public class RequiredElementsAssertionState extends AssertionState implements 
Assertable {
 
-    private final Map<List<QName>, Boolean> pathElements = new HashMap<>();
+    private final Map<PolicyUtils.ElementPath, Boolean> pathElements = new 
HashMap<>();
     private PolicyAsserter policyAsserter;
 
     public RequiredElementsAssertionState(AbstractSecurityAssertion assertion,
                                           PolicyAsserter policyAsserter,
-                                          boolean asserted) {
+                                          boolean asserted) throws 
WSSPolicyException {
         super(assertion, asserted);
 
         if (assertion instanceof RequiredElements) {
             RequiredElements requiredElements = (RequiredElements) assertion;
             for (int i = 0; i < requiredElements.getXPaths().size(); i++) {
                 XPath xPath = requiredElements.getXPaths().get(i);
-                List<QName> elements = PolicyUtils.getElementPath(xPath);
+                PolicyUtils.ElementPath elements = 
PolicyUtils.getElementPathDescriptor(xPath);
                 pathElements.put(elements, Boolean.FALSE);
             }
         }
@@ -73,7 +73,7 @@ public class RequiredElementsAssertionState extends 
AssertionState implements As
     }
 
     public void addElement(List<QName> pathElement) {
-        this.pathElements.put(pathElement, Boolean.FALSE);
+        this.pathElements.put(PolicyUtils.absoluteElementPath(pathElement), 
Boolean.FALSE);
     }
 
     @Override
@@ -87,11 +87,11 @@ public class RequiredElementsAssertionState extends 
AssertionState implements As
     public boolean assertEvent(SecurityEvent securityEvent) throws 
WSSPolicyException {
         RequiredElementSecurityEvent requiredElementSecurityEvent = 
(RequiredElementSecurityEvent) securityEvent;
 
-        Iterator<Map.Entry<List<QName>, Boolean>> elementMapIterator = 
pathElements.entrySet().iterator();
+        Iterator<Map.Entry<PolicyUtils.ElementPath, Boolean>> 
elementMapIterator = pathElements.entrySet().iterator();
         while (elementMapIterator.hasNext()) {
-            Map.Entry<List<QName>, Boolean> next = elementMapIterator.next();
-            List<QName> qNameList = next.getKey();
-            if (WSSUtils.pathMatches(qNameList, 
requiredElementSecurityEvent.getElementPath())) {
+            Map.Entry<PolicyUtils.ElementPath, Boolean> next = 
elementMapIterator.next();
+            PolicyUtils.ElementPath pathElement = next.getKey();
+            if 
(pathElement.matches(requiredElementSecurityEvent.getElementPath())) {
                 next.setValue(Boolean.TRUE);
                 break;
             }
@@ -104,11 +104,11 @@ public class RequiredElementsAssertionState extends 
AssertionState implements As
     @Override
     public boolean isAsserted() {
         clearErrorMessage();
-        Iterator<Map.Entry<List<QName>, Boolean>> elementMapIterator = 
pathElements.entrySet().iterator();
+        Iterator<Map.Entry<PolicyUtils.ElementPath, Boolean>> 
elementMapIterator = pathElements.entrySet().iterator();
         while (elementMapIterator.hasNext()) {
-            Map.Entry<List<QName>, Boolean> next = elementMapIterator.next();
+            Map.Entry<PolicyUtils.ElementPath, Boolean> next = 
elementMapIterator.next();
             if (Boolean.FALSE.equals(next.getValue())) {
-                setErrorMessage("Element " + 
WSSUtils.pathAsString(next.getKey()) + " must be present");
+                setErrorMessage("Element " + 
WSSUtils.pathAsString(next.getKey().getPath()) + " must be present");
                 policyAsserter.unassertPolicy(getAssertion(), 
getErrorMessage());
                 return false;
             }
diff --git 
a/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/SignedElementsAssertionState.java
 
b/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/SignedElementsAssertionState.java
index 0872f609d..cc1bae646 100644
--- 
a/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/SignedElementsAssertionState.java
+++ 
b/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/assertionStates/SignedElementsAssertionState.java
@@ -44,19 +44,19 @@ import java.util.List;
  */
 public class SignedElementsAssertionState extends AssertionState implements 
Assertable {
 
-    private final List<List<QName>> pathElements = new ArrayList<>();
+    private final List<PolicyUtils.ElementPath> pathElements = new 
ArrayList<>();
     private PolicyAsserter policyAsserter;
 
     public SignedElementsAssertionState(AbstractSecurityAssertion assertion,
                                         PolicyAsserter policyAsserter,
-                                        boolean asserted) {
+                                        boolean asserted) throws 
WSSPolicyException {
         super(assertion, asserted);
 
         if (assertion instanceof SignedElements) {
             SignedElements signedElements = (SignedElements) assertion;
             for (int i = 0; i < signedElements.getXPaths().size(); i++) {
                 XPath xPath = signedElements.getXPaths().get(i);
-                List<QName> elements = PolicyUtils.getElementPath(xPath);
+                PolicyUtils.ElementPath elements = 
PolicyUtils.getElementPathDescriptor(xPath);
                 pathElements.add(elements);
             }
         }
@@ -80,17 +80,17 @@ public class SignedElementsAssertionState extends 
AssertionState implements Asse
     }
 
     public void addElement(List<QName> pathElement) {
-        this.pathElements.add(pathElement);
+        this.pathElements.add(PolicyUtils.absoluteElementPath(pathElement));
     }
 
     @Override
     public boolean assertEvent(SecurityEvent securityEvent) throws 
WSSPolicyException {
         AbstractSecuredElementSecurityEvent signedSecurityEvent = 
(AbstractSecuredElementSecurityEvent) securityEvent;
 
-        Iterator<List<QName>> pathElementIterator = pathElements.iterator();
+        Iterator<PolicyUtils.ElementPath> pathElementIterator = 
pathElements.iterator();
         while (pathElementIterator.hasNext()) {
-            List<QName> pathElements = pathElementIterator.next();
-            if (WSSUtils.pathMatches(pathElements, 
signedSecurityEvent.getElementPath())) {
+            PolicyUtils.ElementPath pathElement = pathElementIterator.next();
+            if (pathElement.matches(signedSecurityEvent.getElementPath())) {
                 if (signedSecurityEvent.isSigned()) {
                     setAsserted(true);
                     policyAsserter.assertPolicy(getAssertion());
diff --git 
a/ws-security-policy-stax/src/test/java/org/apache/wss4j/policy/stax/test/AsymmetricBindingIntegrationTest.java
 
b/ws-security-policy-stax/src/test/java/org/apache/wss4j/policy/stax/test/AsymmetricBindingIntegrationTest.java
index 7a4711a8c..55f751b42 100644
--- 
a/ws-security-policy-stax/src/test/java/org/apache/wss4j/policy/stax/test/AsymmetricBindingIntegrationTest.java
+++ 
b/ws-security-policy-stax/src/test/java/org/apache/wss4j/policy/stax/test/AsymmetricBindingIntegrationTest.java
@@ -2716,20 +2716,11 @@ public class AsymmetricBindingIntegrationTest extends 
AbstractPolicyTestBase {
                         "                    <sp:Header Name=\"Header1\" 
Namespace=\"...\"/>\n" +
                         "                    <sp:Header 
Namespace=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\"/>\n"
 +
                         "                </sp:SignedParts>\n" +
-                        "                <sp:SignedElements>\n" +
-                        "                    <sp:XPath 
xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\";>wsu:Created</sp:XPath>\n"
 +
-                        "                </sp:SignedElements>\n" +
                         "                <sp:EncryptedParts>\n" +
                         "                    <sp:Body/>\n" +
                         "                    <sp:Header Name=\"Header2\" 
Namespace=\"...\"/>\n" +
                         "                    <sp:Header 
Namespace=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\"/>\n"
 +
                         "                </sp:EncryptedParts>\n" +
-                        "                <sp:EncryptedElements>\n" +
-                        "                    <sp:XPath 
xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\";>wsu:Created</sp:XPath>\n"
 +
-                        "                </sp:EncryptedElements>\n" +
-                        "                <sp:ContentEncryptedElements>\n" +
-                        "                    <sp:XPath 
xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\";>wsu:Expires</sp:XPath>\n"
 +
-                        "                </sp:ContentEncryptedElements>\n" +
                         "            </wsp:All>\n" +
                         "        </wsp:ExactlyOne>";
 
@@ -2830,20 +2821,11 @@ public class AsymmetricBindingIntegrationTest extends 
AbstractPolicyTestBase {
                         "                    <sp:Header Name=\"Header1\" 
Namespace=\"...\"/>\n" +
                         "                    <sp:Header 
Namespace=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\"/>\n"
 +
                         "                </sp:SignedParts>\n" +
-                        "                <sp:SignedElements>\n" +
-                        "                    <sp:XPath 
xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\";>wsu:Created</sp:XPath>\n"
 +
-                        "                </sp:SignedElements>\n" +
                         "                <sp:EncryptedParts>\n" +
                         "                    <sp:Body/>\n" +
                         "                    <sp:Header Name=\"Header2\" 
Namespace=\"...\"/>\n" +
                         "                    <sp:Header 
Namespace=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\"/>\n"
 +
                         "                </sp:EncryptedParts>\n" +
-                        "                <sp:EncryptedElements>\n" +
-                        "                    <sp:XPath 
xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\";>wsu:Created</sp:XPath>\n"
 +
-                        "                </sp:EncryptedElements>\n" +
-                        "                <sp:ContentEncryptedElements>\n" +
-                        "                    <sp:XPath 
xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\";>wsu:Expires</sp:XPath>\n"
 +
-                        "                </sp:ContentEncryptedElements>\n" +
                         "            </wsp:All>\n" +
                         "        </wsp:ExactlyOne>";
 
diff --git 
a/ws-security-policy-stax/src/test/java/org/apache/wss4j/policy/stax/test/SignedElementsTest.java
 
b/ws-security-policy-stax/src/test/java/org/apache/wss4j/policy/stax/test/SignedElementsTest.java
index 12a7f66b0..bcd41cf54 100644
--- 
a/ws-security-policy-stax/src/test/java/org/apache/wss4j/policy/stax/test/SignedElementsTest.java
+++ 
b/ws-security-policy-stax/src/test/java/org/apache/wss4j/policy/stax/test/SignedElementsTest.java
@@ -25,15 +25,18 @@ import java.util.List;
 import javax.xml.namespace.QName;
 
 import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.common.WSSPolicyException;
 import org.apache.wss4j.policy.stax.PolicyViolationException;
 import org.apache.wss4j.policy.stax.enforcer.PolicyEnforcer;
 import org.apache.wss4j.stax.ext.WSSConstants;
 import org.apache.wss4j.stax.securityEvent.OperationSecurityEvent;
+import org.apache.wss4j.stax.utils.WSSUtils;
 import org.apache.xml.security.stax.ext.XMLSecurityConstants;
 import org.apache.xml.security.stax.securityEvent.SignedElementSecurityEvent;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
@@ -103,4 +106,50 @@ public class SignedElementsTest extends 
AbstractPolicyTestBase {
             assertEquals(e.getFaultCode(), 
WSSecurityException.INVALID_SECURITY);
         }
     }
+
+    @Test
+    public void testRelativeXPathMustBeSigned() throws Exception {
+        String policyString =
+                "<sp:SignedElements 
xmlns:sp=\"http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702\";>\n" +
+                        "<sp:XPath 
xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\";>wsu:Created</sp:XPath>\n"
 +
+                        "</sp:SignedElements>";
+        PolicyEnforcer policyEnforcer = 
buildAndStartPolicyEngine(policyString);
+
+        OperationSecurityEvent operationSecurityEvent = new 
OperationSecurityEvent();
+        operationSecurityEvent.setOperation(WSDL_DEFINITIONS);
+        policyEnforcer.registerSecurityEvent(operationSecurityEvent);
+
+        List<QName> createdPath = new ArrayList<>();
+        createdPath.addAll(WSSConstants.SOAP_11_WSSE_SECURITY_HEADER_PATH);
+        createdPath.add(WSSConstants.TAG_WSU_TIMESTAMP);
+        createdPath.add(WSSConstants.TAG_WSU_CREATED);
+        SignedElementSecurityEvent signedElementSecurityEvent = new 
SignedElementSecurityEvent(null, false, null);
+        signedElementSecurityEvent.setElementPath(createdPath);
+
+        try {
+            policyEnforcer.registerSecurityEvent(signedElementSecurityEvent);
+            fail("Exception expected");
+        } catch (WSSecurityException e) {
+            assertTrue(e.getCause() instanceof PolicyViolationException);
+            assertEquals(e.getCause().getMessage(),
+                    "Element " + WSSUtils.pathAsString(createdPath) + " must 
be signed");
+            assertEquals(e.getFaultCode(), 
WSSecurityException.INVALID_SECURITY);
+        }
+    }
+
+    @Test
+    public void testUnsupportedXPathIsRejected() throws Exception {
+        String policyString =
+                "<sp:SignedElements 
xmlns:sp=\"http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702\";>\n" +
+                        "<sp:XPath 
xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\";>//wsu:Created</sp:XPath>\n"
 +
+                        "</sp:SignedElements>";
+
+        PolicyEnforcer policyEnforcer = 
buildAndStartPolicyEngine(policyString);
+        OperationSecurityEvent operationSecurityEvent = new 
OperationSecurityEvent();
+        operationSecurityEvent.setOperation(WSDL_DEFINITIONS);
+
+        WSSecurityException exception = assertThrows(WSSecurityException.class,
+                () -> 
policyEnforcer.registerSecurityEvent(operationSecurityEvent));
+        assertTrue(exception.getCause() instanceof WSSPolicyException);
+    }
 }
\ No newline at end of file

Reply via email to