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
commit 5aba725a8144aba4e04e1b588afcdbaa7d591460 Author: Colm O hEigeartaigh <[email protected]> AuthorDate: Mon Sep 21 12:23:14 2026 +0100 Revert "Fix SenderVouches EncryptedKey case (#718)" This reverts commit 1e8eb1f29039fcaaabbc8abd3c930e30c4709a79. --- .../org/apache/wss4j/dom/saml/DOMSAMLUtil.java | 35 ----- .../SamlSenderVouchesVouchingIdentityTest.java | 170 --------------------- 2 files changed, 205 deletions(-) diff --git a/ws-security-dom/src/main/java/org/apache/wss4j/dom/saml/DOMSAMLUtil.java b/ws-security-dom/src/main/java/org/apache/wss4j/dom/saml/DOMSAMLUtil.java index 30bda991c..68be6eabd 100644 --- a/ws-security-dom/src/main/java/org/apache/wss4j/dom/saml/DOMSAMLUtil.java +++ b/ws-security-dom/src/main/java/org/apache/wss4j/dom/saml/DOMSAMLUtil.java @@ -242,26 +242,6 @@ public final class DOMSAMLUtil { return true; } - - /** - * Whether a signature result identifies the sender that produced it, as opposed to merely - * proving possession of a key. - * - * @param signedResult a SIGN or UT_SIGN result - * @return true if a trust decision was taken on the signing credential, or the signature was - * made with a key derived from a UsernameToken whose password was verified - */ - private static boolean establishesSenderIdentity(WSSecurityEngineResult signedResult) { - if (Boolean.TRUE.equals(signedResult.get(WSSecurityEngineResult.TAG_VALIDATED_TOKEN))) { - return true; - } - - // A UsernameToken derived key is not stamped as a validated token - no Validator runs on - // the signing credential itself - but the token's password was verified before the key was - // derived from it, so the sender is authenticated all the same. - Integer action = (Integer)signedResult.get(WSSecurityEngineResult.TAG_ACTION); - return action != null && WSConstants.UT_SIGN == action.intValue(); - } /** * Return true if there is a signature which references the Assertion and the SOAP Body. * @param assertionWrapper the SamlAssertionWrapper object @@ -274,22 +254,7 @@ public final class DOMSAMLUtil { Element body, List<WSSecurityEngineResult> signed ) { - // A sender-vouches assertion is only worth as much as the identity of whoever vouched for - // it. An assertion that is itself signed carries that backing already - the signature was - // trust-verified against its issuer (see SamlAssertionValidator.verifySignedAssertion) - - // and the message signature merely binds it to this message, so any signature will do. - // - // An unsigned assertion has no such backing. The only party asserting it is whoever signed - // the message, so that signature has to have been made with a credential whose identity was - // actually established. A signature verified with a bare symmetric key - one taken from an - // EncryptedKey that the sender minted for itself, say - proves possession of that key and - // nothing whatsoever about who sent it, and so cannot vouch for anybody. - boolean vouchingIdentityRequired = !assertionWrapper.isSigned(); - for (WSSecurityEngineResult signedResult : signed) { - if (vouchingIdentityRequired && !establishesSenderIdentity(signedResult)) { - continue; - } @SuppressWarnings("unchecked") List<WSDataRef> sl = (List<WSDataRef>)signedResult.get( diff --git a/ws-security-dom/src/test/java/org/apache/wss4j/dom/saml/SamlSenderVouchesVouchingIdentityTest.java b/ws-security-dom/src/test/java/org/apache/wss4j/dom/saml/SamlSenderVouchesVouchingIdentityTest.java deleted file mode 100644 index b5c22567d..000000000 --- a/ws-security-dom/src/test/java/org/apache/wss4j/dom/saml/SamlSenderVouchesVouchingIdentityTest.java +++ /dev/null @@ -1,170 +0,0 @@ -/** - * 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.wss4j.dom.saml; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.apache.wss4j.common.crypto.Crypto; -import org.apache.wss4j.common.crypto.CryptoFactory; -import org.apache.wss4j.common.saml.SAMLCallback; -import org.apache.wss4j.common.saml.SAMLUtil; -import org.apache.wss4j.common.saml.SamlAssertionWrapper; -import org.apache.wss4j.common.saml.builder.SAML1Constants; -import org.apache.wss4j.common.util.SOAPUtil; -import org.apache.wss4j.dom.WSConstants; -import org.apache.wss4j.dom.WSDataRef; -import org.apache.wss4j.dom.common.SAML1CallbackHandler; -import org.apache.wss4j.dom.engine.WSSConfig; -import org.apache.wss4j.dom.engine.WSSecurityEngineResult; -import org.apache.wss4j.dom.util.WSSecurityUtil; -import org.junit.jupiter.api.Test; -import org.w3c.dom.Document; -import org.w3c.dom.Element; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -/** - * A sender-vouches assertion is a claim made by whoever sent the message, so it is worth exactly as - * much as that sender's identity. An assertion that is itself signed carries its issuer's signature, - * which is trust-verified separately; an unsigned one does not, and the only thing asserting it is - * the signature over the message. That signature therefore has to have been made with a credential - * whose identity was established - not merely with a key the sender happens to hold, such as one - * taken from an EncryptedKey the sender minted for itself. - */ -public class SamlSenderVouchesVouchingIdentityTest { - - private final Crypto crypto; - - public SamlSenderVouchesVouchingIdentityTest() throws Exception { - WSSConfig.init(); - crypto = CryptoFactory.getInstance(); - } - - /** - * The shape of the bypass: an unsigned sender-vouches assertion, and a signature that covers it - * and the Body but was verified with a bare symmetric key, so it says nothing about who sent it. - */ - @Test - public void testUnsignedAssertionRejectsUnidentifiedSigner() throws Exception { - Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG); - SamlAssertionWrapper assertion = senderVouchesAssertion(doc, false); - Element body = WSSecurityUtil.findBodyElement(doc); - - List<WSSecurityEngineResult> signed = Collections.singletonList( - coveringSignature(WSConstants.SIGN, false, assertion.getElement(), body)); - - assertFalse(DOMSAMLUtil.checkSenderVouches(assertion, null, body, signed), - "An unsigned sender-vouches assertion must not be accepted on the word of a signer " - + "whose identity was never established"); - } - - /** - * The same coverage from a credential a Validator made a trust decision about is what - * sender-vouches is supposed to look like. - */ - @Test - public void testUnsignedAssertionAcceptsTrustValidatedSigner() throws Exception { - Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG); - SamlAssertionWrapper assertion = senderVouchesAssertion(doc, false); - Element body = WSSecurityUtil.findBodyElement(doc); - - List<WSSecurityEngineResult> signed = Collections.singletonList( - coveringSignature(WSConstants.SIGN, true, assertion.getElement(), body)); - - assertTrue(DOMSAMLUtil.checkSenderVouches(assertion, null, body, signed)); - } - - /** - * A UsernameToken derived key is never stamped as a validated token, but deriving it required - * the password, so the sender is authenticated and may vouch. - */ - @Test - public void testUnsignedAssertionAcceptsUsernameTokenSigner() throws Exception { - Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG); - SamlAssertionWrapper assertion = senderVouchesAssertion(doc, false); - Element body = WSSecurityUtil.findBodyElement(doc); - - List<WSSecurityEngineResult> signed = Collections.singletonList( - coveringSignature(WSConstants.UT_SIGN, false, assertion.getElement(), body)); - - assertTrue(DOMSAMLUtil.checkSenderVouches(assertion, null, body, signed)); - } - - /** - * An assertion signed by its issuer already carries a vouching identity of its own - the - * message signature only binds it to this message - so the symmetric-binding deployments that - * rely on that pattern must keep working. - */ - @Test - public void testSignedAssertionAcceptsAnySigner() throws Exception { - Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG); - SamlAssertionWrapper assertion = senderVouchesAssertion(doc, true); - assertTrue(assertion.isSigned(), "precondition: the assertion is signed"); - Element body = WSSecurityUtil.findBodyElement(doc); - - List<WSSecurityEngineResult> signed = Collections.singletonList( - coveringSignature(WSConstants.SIGN, false, assertion.getElement(), body)); - - assertTrue(DOMSAMLUtil.checkSenderVouches(assertion, null, body, signed)); - } - - private SamlAssertionWrapper senderVouchesAssertion(Document doc, boolean sign) throws Exception { - SAML1CallbackHandler callbackHandler = new SAML1CallbackHandler(); - callbackHandler.setStatement(SAML1CallbackHandler.Statement.AUTHN); - callbackHandler.setConfirmationMethod(SAML1Constants.CONF_SENDER_VOUCHES); - callbackHandler.setIssuer("www.example.com"); - - SAMLCallback samlCallback = new SAMLCallback(); - SAMLUtil.doSAMLCallback(callbackHandler, samlCallback); - - SamlAssertionWrapper samlAssertion = new SamlAssertionWrapper(samlCallback); - if (sign) { - samlAssertion.signAssertion("16c73ab6-b892-458f-abf5-2f875f74882e", "security", - crypto, false); - } - samlAssertion.toDOM(doc); - return samlAssertion; - } - - /** - * A signature result covering the given elements. {@code validated} is what - * SignatureProcessor stamps when a trust decision was actually taken on the signing credential. - */ - private WSSecurityEngineResult coveringSignature( - int action, boolean validated, Element... protectedElements - ) { - List<WSDataRef> dataRefs = new ArrayList<>(); - for (Element protectedElement : protectedElements) { - WSDataRef dataRef = new WSDataRef(); - dataRef.setProtectedElement(protectedElement); - dataRefs.add(dataRef); - } - - WSSecurityEngineResult result = new WSSecurityEngineResult(action); - result.put(WSSecurityEngineResult.TAG_DATA_REF_URIS, dataRefs); - if (validated) { - result.put(WSSecurityEngineResult.TAG_VALIDATED_TOKEN, Boolean.TRUE); - } - return result; - } -}
