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


The following commit(s) were added to refs/heads/master by this push:
     new 27344d91 Test that RahasData takes no identity from a bare 
BinarySecurityToken
27344d91 is described below

commit 27344d912e1c511fca0889cdd100a8b48529c856
Author: Robert Lazarski <[email protected]>
AuthorDate: Fri Oct 9 08:07:19 2026 -1000

    Test that RahasData takes no identity from a bare BinarySecurityToken
    
    Covers the STS half of d0d8ff88: a BST alone must not authenticate, and one
    placed after a verified signature must not replace its principal or client
    certificate. Both tests fail against the code before that commit.
    
    Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
 .../test/java/org/apache/rahas/RahasDataTest.java  | 139 +++++++++++++++++++++
 1 file changed, 139 insertions(+)

diff --git 
a/modules/rampart-trust/src/test/java/org/apache/rahas/RahasDataTest.java 
b/modules/rampart-trust/src/test/java/org/apache/rahas/RahasDataTest.java
new file mode 100644
index 00000000..41f78193
--- /dev/null
+++ b/modules/rampart-trust/src/test/java/org/apache/rahas/RahasDataTest.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.rahas;
+
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.security.KeyStore;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.axiom.om.OMAbstractFactory;
+import org.apache.axiom.om.util.AXIOMUtil;
+import org.apache.axiom.soap.SOAPEnvelope;
+import org.apache.axis2.context.MessageContext;
+import org.apache.wss4j.dom.WSConstants;
+import org.apache.wss4j.dom.engine.WSSecurityEngineResult;
+import org.apache.wss4j.dom.handler.WSHandlerConstants;
+import org.apache.wss4j.dom.handler.WSHandlerResult;
+
+/**
+ * The STS principal and proof-key certificate must come only from verified
+ * signature or UsernameToken results, never from a bare BinarySecurityToken.
+ *
+ * <p>Nothing validates a BST on its own: it need not be trusted and the 
sender need
+ * not hold its private key. RahasData used to take a BST's SubjectDN as the
+ * principal and its certificate as the client certificate, so a requestor 
could be
+ * issued an assertion for any identity, bound to a certificate of its 
choosing.</p>
+ */
+public class RahasDataTest extends TestCase {
+
+    private static final String RST =
+            "<wst:RequestSecurityToken 
xmlns:wst=\"http://docs.oasis-open.org/ws-sx/ws-trust/200512\";>"
+            + 
"<wst:RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</wst:RequestType>"
+            + "</wst:RequestSecurityToken>";
+
+    /** Stands in for the certificate a verified signature was made with. */
+    private X509Certificate signerCert;
+
+    /** Stands in for an arbitrary certificate an attacker places in a BST. */
+    private X509Certificate bstCert;
+
+    protected void setUp() throws Exception {
+        KeyStore keyStore = KeyStore.getInstance("JKS");
+        try (InputStream in = new 
FileInputStream("src/test/resources/keystore.jks")) {
+            keyStore.load(in, "password".toCharArray());
+        }
+        signerCert = (X509Certificate) keyStore.getCertificate("apache");
+
+        try (InputStream in = new 
FileInputStream("src/test/resources/apache.crt")) {
+            bstCert = (X509Certificate) CertificateFactory.getInstance("X.509")
+                    .generateCertificate(in);
+        }
+
+        assertFalse("the test needs two distinct identities",
+                
signerCert.getSubjectX500Principal().equals(bstCert.getSubjectX500Principal()));
+    }
+
+    private static WSSecurityEngineResult signatureResult(X509Certificate 
cert) {
+        WSSecurityEngineResult result = new 
WSSecurityEngineResult(WSConstants.SIGN);
+        result.put(WSSecurityEngineResult.TAG_PRINCIPAL, 
cert.getSubjectX500Principal());
+        result.put(WSSecurityEngineResult.TAG_X509_CERTIFICATE, cert);
+        return result;
+    }
+
+    private static WSSecurityEngineResult bstResult(X509Certificate cert) {
+        WSSecurityEngineResult result = new 
WSSecurityEngineResult(WSConstants.BST);
+        result.put(WSSecurityEngineResult.TAG_X509_CERTIFICATES, new 
X509Certificate[] {cert});
+        return result;
+    }
+
+    private static MessageContext requestWith(WSSecurityEngineResult... 
results)
+            throws Exception {
+        List<WSSecurityEngineResult> engineResults = new 
ArrayList<WSSecurityEngineResult>();
+        Collections.addAll(engineResults, results);
+        List<WSHandlerResult> handlerResults = new 
ArrayList<WSHandlerResult>();
+        handlerResults.add(new WSHandlerResult(null, engineResults,
+                Collections.<Integer, 
List<WSSecurityEngineResult>>emptyMap()));
+
+        SOAPEnvelope envelope = 
OMAbstractFactory.getSOAP11Factory().getDefaultEnvelope();
+        envelope.getBody().addChild(AXIOMUtil.stringToOM(RST));
+
+        MessageContext msgCtx = new MessageContext();
+        msgCtx.setEnvelope(envelope);
+        msgCtx.setProperty(WSHandlerConstants.RECV_RESULTS, handlerResults);
+        return msgCtx;
+    }
+
+    /** A BST alone establishes no identity, so the request must be refused. */
+    public void testBareBstDoesNotAuthenticate() throws Exception {
+        try {
+            RahasData data = new RahasData(requestWith(bstResult(bstCert)));
+            fail("a bare BST must not yield a principal, but got " + 
data.getPrincipal());
+        } catch (TrustException expected) {
+            // no verified principal and no SAML assertion: REQUEST_FAILED
+        }
+    }
+
+    /**
+     * Results are walked in the order the elements appear in the message, 
which the
+     * sender controls. A BST placed after a verified signature must not 
replace the
+     * identity or the proof-key certificate that the signature established.
+     */
+    public void testBstAfterSignatureDoesNotOverrideIdentity() throws 
Exception {
+        RahasData data = new RahasData(
+                requestWith(signatureResult(signerCert), bstResult(bstCert)));
+
+        assertEquals(signerCert.getSubjectX500Principal(), 
data.getPrincipal());
+        assertSame(signerCert, data.getClientCert());
+    }
+
+    /** Control: a verified signature alone still authenticates the requestor. 
*/
+    public void testSignatureEstablishesIdentity() throws Exception {
+        RahasData data = new 
RahasData(requestWith(signatureResult(signerCert)));
+
+        assertEquals(signerCert.getSubjectX500Principal(), 
data.getPrincipal());
+        assertSame(signerCert, data.getClientCert());
+    }
+}

Reply via email to