This is an automated email from the ASF dual-hosted git repository.

robertlazarski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-java-rampart.git

commit 205ae0c19bd5b0889cf91504a89cca2c950c9428
Author: Robert Lazarski <[email protected]>
AuthorDate: Wed Jun 10 05:53:43 2026 -1000

    RAMPART-431: skip signing SignedParts headers that are absent from the 
message
    
    TransportBindingBuilder built signature parts directly from the policy's
    SignedParts headers without checking whether each header is actually 
present in
    the message. When a header listed in SignedParts is missing - e.g. the
    WS-Addressing wsa:To header in an STS bootstrap / SecureConversation 
request -
    WSS4J fails the whole send with "General security error ... Element to
    encrypt/sign not found: http://www.w3.org/2005/08/addressing, To".
    
    The four signature methods (X509 / Kerberos / IssuedToken / 
SecureConversation)
    now add a SignedParts header only if a matching element exists in the SOAP 
header,
    via the new addSignedPartHeaderIfPresent helper. This mirrors RampartUtil's
    outbound part resolution and the inbound validator, both of which treat an 
absent
    signed-parts header as allowed.
    
    Adds a regression test 
(TransportBindingBuilderTest.testTransportBindingAbsentSignedHeader
    with rampart-transport-binding-absent-signed-header.xml): a policy whose 
endorsing
    token signs a 2005/08 wsa:To header not present in the message now builds
    successfully. With the presence check disabled the test reproduces the 
original
    "Element to encrypt/sign not found" error. Verified with a full clean
    -Papache-release verify across all modules including the nine policy 
samples on
    JDK 25.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
---
 .../rampart/builder/TransportBindingBuilder.java   | 49 ++++++++++-----
 .../rampart/TransportBindingBuilderTest.java       | 23 +++++++
 ...part-transport-binding-absent-signed-header.xml | 70 ++++++++++++++++++++++
 3 files changed, 126 insertions(+), 16 deletions(-)

diff --git 
a/modules/rampart-core/src/main/java/org/apache/rampart/builder/TransportBindingBuilder.java
 
b/modules/rampart-core/src/main/java/org/apache/rampart/builder/TransportBindingBuilder.java
index 5e37596f..cc065a47 100644
--- 
a/modules/rampart-core/src/main/java/org/apache/rampart/builder/TransportBindingBuilder.java
+++ 
b/modules/rampart-core/src/main/java/org/apache/rampart/builder/TransportBindingBuilder.java
@@ -18,6 +18,7 @@ package org.apache.rampart.builder;
 
 import org.apache.axiom.om.OMElement;
 import org.apache.axiom.soap.SOAPEnvelope;
+import org.apache.axiom.soap.SOAPHeader;
 import org.apache.axis2.context.MessageContext;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -55,6 +56,7 @@ import javax.crypto.KeyGenerator;
 import javax.xml.crypto.dsig.Reference;
 import javax.xml.crypto.dsig.SignatureMethod;
 
+import javax.xml.namespace.QName;
 import java.util.ArrayList;
 import java.util.Base64;
 import java.util.Iterator;
@@ -185,6 +187,33 @@ public class TransportBindingBuilder extends 
BindingBuilder {
      * @param token
      * @param signdParts 
      */
+    /**
+     * Adds a SignedParts header to the list of signature parts, but only if a 
matching
+     * header is actually present in the message. Signing a part that is not 
present
+     * makes WSS4J fail with "Element to encrypt/sign not found" - for example 
when a
+     * policy lists wsa:To in SignedParts but the WS-Addressing headers are 
absent, as
+     * happens for an STS bootstrap request (RAMPART-431). This mirrors the 
inbound
+     * validator, which treats an absent signed-parts header as allowed.
+     */
+    private void addSignedPartHeaderIfPresent(List<WSEncryptionPart> sigParts,
+            SOAPEnvelope envelope, Header header) {
+        SOAPHeader soapHeader = envelope.getHeader();
+        if (soapHeader == null) {
+            return;
+        }
+        boolean present;
+        if (header.getName() == null) {
+            // The policy matches all headers in the namespace.
+            present = 
!soapHeader.getHeaderBlocksWithNSURI(header.getNamespace()).isEmpty();
+        } else {
+            present = soapHeader.getFirstChildWithName(
+                    new QName(header.getNamespace(), header.getName())) != 
null;
+        }
+        if (present) {
+            sigParts.add(new WSEncryptionPart(header.getName(), 
header.getNamespace(), "Content"));
+        }
+    }
+
     private byte[] doX509TokenSignature(RampartMessageData rmd, Token token, 
SignedEncryptedParts signdParts) throws RampartException {
         
         RampartPolicyData rpd = rmd.getPolicyData();
@@ -205,10 +234,7 @@ public class TransportBindingBuilder extends 
BindingBuilder {
             ArrayList headers = signdParts.getHeaders();
             for (Iterator iterator = headers.iterator(); iterator.hasNext();) {
                 Header header = (Header) iterator.next();
-                WSEncryptionPart wep = new WSEncryptionPart(header.getName(), 
-                        header.getNamespace(),
-                        "Content");
-                sigParts.add(wep);
+                addSignedPartHeaderIfPresent(sigParts, 
rmd.getMsgContext().getEnvelope(), header);
             }
         }
         if(token.isDerivedKeys()) {
@@ -345,10 +371,7 @@ public class TransportBindingBuilder extends 
BindingBuilder {
             ArrayList headers = signdParts.getHeaders();
             for (Iterator iterator = headers.iterator(); iterator.hasNext();) {
                 Header header = (Header) iterator.next();
-                WSEncryptionPart wep = new WSEncryptionPart(header.getName(), 
-                        header.getNamespace(),
-                        "Content");
-                sigParts.add(wep);
+                addSignedPartHeaderIfPresent(sigParts, 
rmd.getMsgContext().getEnvelope(), header);
             }
         }
 
@@ -457,10 +480,7 @@ public class TransportBindingBuilder extends 
BindingBuilder {
             ArrayList headers = signdParts.getHeaders();
             for (Object signedHeader : headers) {
                 Header header = (Header) signedHeader;
-                WSEncryptionPart wep = new WSEncryptionPart(header.getName(),
-                        header.getNamespace(),
-                        "Content");
-                sigParts.add(wep);
+                addSignedPartHeaderIfPresent(sigParts, 
rmd.getMsgContext().getEnvelope(), header);
             }
         }
         
@@ -610,10 +630,7 @@ public class TransportBindingBuilder extends 
BindingBuilder {
             ArrayList headers = signdParts.getHeaders();
             for (Object objectHeader : headers) {
                 Header header = (Header) objectHeader;
-                WSEncryptionPart wep = new WSEncryptionPart(header.getName(),
-                        header.getNamespace(),
-                        "Content");
-                sigParts.add(wep);
+                addSignedPartHeaderIfPresent(sigParts, 
rmd.getMsgContext().getEnvelope(), header);
             }
         }
         
diff --git 
a/modules/rampart-tests/src/test/java/org/apache/rampart/TransportBindingBuilderTest.java
 
b/modules/rampart-tests/src/test/java/org/apache/rampart/TransportBindingBuilderTest.java
index a39e3619..99019e6b 100644
--- 
a/modules/rampart-tests/src/test/java/org/apache/rampart/TransportBindingBuilderTest.java
+++ 
b/modules/rampart-tests/src/test/java/org/apache/rampart/TransportBindingBuilderTest.java
@@ -46,6 +46,29 @@ public class TransportBindingBuilderTest extends 
MessageBuilderTestBase {
         this.verifySecHeader(list.iterator(), ctx.getEnvelope());
     }
 
+    public void testTransportBindingAbsentSignedHeader() throws Exception {
+        // RAMPART-431: the policy lists a WS-Addressing 2005/08 "To" header 
in the
+        // endorsing token's SignedParts, but the message does not contain 
that header.
+        // The build must succeed (the absent header is skipped) rather than 
fail with
+        // "Element to encrypt/sign not found: 
http://www.w3.org/2005/08/addressing, To".
+        MessageContext ctx = getMsgCtx();
+
+        String policyXml = 
"test-resources/policy/rampart-transport-binding-absent-signed-header.xml";
+        Policy policy = this.loadPolicy(policyXml);
+
+        ctx.setProperty(RampartMessageData.KEY_RAMPART_POLICY, policy);
+
+        MessageBuilder builder = new MessageBuilder();
+        builder.build(ctx);
+
+        List<QName> list = new ArrayList<QName>();
+        list.add(new QName(WSConstants.WSU_NS, 
WSConstants.TIMESTAMP_TOKEN_LN));
+        list.add(new QName(WSConstants.WSSE_NS, 
WSConstants.USERNAME_TOKEN_LN));
+        list.add(new QName(WSConstants.WSSE_NS, WSConstants.BINARY_TOKEN_LN));
+        list.add(new QName(WSConstants.SIG_NS, WSConstants.SIG_LN));
+        this.verifySecHeader(list.iterator(), ctx.getEnvelope());
+    }
+
     public void testTransportBindingNoBST() throws Exception {
         MessageContext ctx = getMsgCtx();
 
diff --git 
a/modules/rampart-tests/test-resources/policy/rampart-transport-binding-absent-signed-header.xml
 
b/modules/rampart-tests/test-resources/policy/rampart-transport-binding-absent-signed-header.xml
new file mode 100644
index 00000000..6a66a7d5
--- /dev/null
+++ 
b/modules/rampart-tests/test-resources/policy/rampart-transport-binding-absent-signed-header.xml
@@ -0,0 +1,70 @@
+<wsp:Policy wsu:Id="5" 
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
 xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy";>
+<wsp:ExactlyOne>
+  <wsp:All>
+       <sp:TransportBinding 
xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy";>
+         <wsp:Policy>
+               <sp:TransportToken>
+                 <wsp:Policy>
+                       <sp:HttpsToken RequireClientCertificate="false"/>
+                 </wsp:Policy>
+               </sp:TransportToken>
+               <sp:AlgorithmSuite>
+                 <wsp:Policy>
+                       <sp:Basic128/>
+                 </wsp:Policy>
+               </sp:AlgorithmSuite>
+               <sp:Layout>
+                 <wsp:Policy>
+                       <sp:Lax/>
+                 </wsp:Policy>
+               </sp:Layout>
+               <sp:IncludeTimestamp/>
+         </wsp:Policy>
+       </sp:TransportBinding>
+       <sp:SignedSupportingTokens 
xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy";>
+               <wsp:Policy>
+                       <sp:UsernameToken 
sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient";
 />
+         </wsp:Policy>
+       </sp:SignedSupportingTokens>
+       <sp:SignedEndorsingSupportingTokens 
xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy";>
+         <wsp:Policy>
+               <sp:X509Token 
sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient";
 />
+               <!-- RAMPART-431: this WS-Addressing 2005/08 "To" header is NOT 
present in the
+                    test message (which carries a 2004/08 "To"). Signing must 
skip it rather
+                    than fail with "Element to encrypt/sign not found". -->
+               <sp:SignedParts>
+                       <sp:Header Name="To" 
Namespace="http://www.w3.org/2005/08/addressing"/>
+               </sp:SignedParts>
+         </wsp:Policy>
+       </sp:SignedEndorsingSupportingTokens>
+       <sp:Wss10 
xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy";>
+         <wsp:Policy>
+               <sp:MustSupportRefKeyIdentifier/>
+               <sp:MustSupportRefIssuerSerial/>
+         </wsp:Policy>
+       </sp:Wss10>
+       <sp:Trust10 
xmlns:sp="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy";>
+         <wsp:Policy>
+               <sp:MustSupportIssuedTokens/>
+               <sp:RequireClientEntropy/>
+               <sp:RequireServerEntropy/>
+         </wsp:Policy>
+       </sp:Trust10>
+
+       <ramp:RampartConfig xmlns:ramp="http://ws.apache.org/rampart/policy";>
+               <ramp:user>alice</ramp:user>
+               <ramp:encryptionUser>bob</ramp:encryptionUser>
+               
<ramp:passwordCallbackClass>org.apache.rampart.TestCBHandler</ramp:passwordCallbackClass>
+
+               <ramp:signatureCrypto>
+                       <ramp:crypto 
provider="org.apache.ws.security.components.crypto.Merlin">
+                               <ramp:property 
name="org.apache.ws.security.crypto.merlin.keystore.type">pkcs12</ramp:property>
+                               <ramp:property 
name="org.apache.ws.security.crypto.merlin.file">test-resources/keys/interop2024.pkcs12</ramp:property>
+                               <ramp:property 
name="org.apache.ws.security.crypto.merlin.keystore.password">password</ramp:property>
+                       </ramp:crypto>
+               </ramp:signatureCrypto>
+       </ramp:RampartConfig>
+
+  </wsp:All>
+</wsp:ExactlyOne>
+</wsp:Policy>

Reply via email to