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


The following commit(s) were added to refs/heads/2_4_x-fixes by this push:
     new f1af85fa2 Properly wire UsernameToken + RSA15 flags for the streaming 
layer (#717)
f1af85fa2 is described below

commit f1af85fa2b5170d24bbb702c6df75f50db725fb5
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Mon Sep 21 09:29:11 2026 +0100

    Properly wire UsernameToken + RSA15 flags for the streaming layer (#717)
---
 src/site/asciidoc/streaming.adoc                   |  77 ----------
 .../wss4j/policy/stax/enforcer/PolicyEnforcer.java | 124 ++++++++++++++---
 .../policy/stax/enforcer/PolicyInputProcessor.java |  16 ++-
 .../policy/stax/test/ScopedEngineDefaultsTest.java | 155 +++++++++++++++++++++
 .../testdata/wsdl/mixedPasswordPolicies.wsdl       |  98 +++++++++++++
 5 files changed, 369 insertions(+), 101 deletions(-)

diff --git a/src/site/asciidoc/streaming.adoc b/src/site/asciidoc/streaming.adoc
deleted file mode 100644
index 3c4112cfc..000000000
--- a/src/site/asciidoc/streaming.adoc
+++ /dev/null
@@ -1,77 +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.
-//
-
-== Streaming (StAX) WS-Security support in Apache WSS4J&#8482; 2.0.0
-
-=== Overview of new features
-
-WSS4J 2.0.0 introduces a streaming (StAX-based) WS-Security implementation to
-complement the existing DOM-based implementation. The DOM-based implementation
-is quite performant and flexible, but suffers from having to read the entire
-XML tree into memory. For large SOAP requests this can have a detrimental
-impact on performance. In addition, for web services stacks such as Apache CXF
-which are streaming-based, it carries an additional performance penalty of
-having to explicitly convert the request stream to a DOM Element.
-
-The new StAX-based WS-Security implementation does not read the request into
-memory, and hence uses far less memory for large requests. It is also more
-performant in certain circumstances. The StAX-based code offers largely the
-same functionality as that available as part of the DOM code, and is
-configured in mostly the same way (via configuration tags that are shared
-between both stacks). It does not offer the low-level API available in the DOM
-code to individually construct various WS-Security tokens, but instead must be
-used by specifying various actions to perform.
-
-As of the time of writing, Apache CXF is the only web services stack to 
-integrate the new WS-Security streaming functionality. To switch to use the
-streaming code for the manual "Action" based approach, simply change the
-outbound and inbound interceptors as follows:
-
- * "org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor" to
-"org.apache.cxf.ws.security.wss4j.WSS4JStaxOutInterceptor".
- * "org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor" to
-"org.apache.cxf.ws.security.wss4j.WSS4JStaxInInterceptor".
-
-For the WS-SecurityPolicy based approach of configuring WS-Security, simply
-set the JAX-WS property SecurityConstants.ENABLE_STREAMING_SECURITY
-("ws-security.enable.streaming") to "true".
-
-=== Limitations of the streaming WS-Security implementation
-
-The new streaming implementation in WSS4J 2.0.0 meets the vast majority of the
-most common use-cases. However, it does not support everything that the DOM
-implementation supports. The limitations are:
-
- * XPath evaluation is not supported apart from certain simple expressions.
-XPath evaluations are used with WS-SecurityPolicy RequiredElements,
-SignedElements, (Content)EncryptedElements. XPath expressions that point
-directly to the element are supported, e.g. /soap:Envelope/soap:Header/wsa:To.
-See WSS-445.
- * WS-SecurityPolicy "Strict" Layout validation is not enforced. This includes
-enforcing whether a Timestamp is first or last. See WSS-444.
- * A SymmetricBinding policy with a ProtectTokens assertion is not supported.
-See WSS-456.
- * The combination of EncryptBeforeSigning + EncryptSignature policies are not
-supported. See WSS-464.
- * Deriving keys from Username Tokens (Endorsing Username Tokens) are not
-supported.
- * Endorsing tokens don't work with Symmetric + Asymmetric binding on the
-client side, unless the endorsing token is a SAML or IssuedToken.
- * Derived Endorsing Tokens are not supported on the client side.
-
diff --git 
a/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/enforcer/PolicyEnforcer.java
 
b/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/enforcer/PolicyEnforcer.java
index 5e48f7281..c3280c74f 100644
--- 
a/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/enforcer/PolicyEnforcer.java
+++ 
b/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/enforcer/PolicyEnforcer.java
@@ -104,8 +104,10 @@ import 
org.apache.wss4j.policy.stax.assertionStates.X509TokenAssertionState;
 import org.apache.wss4j.stax.ext.WSSConstants;
 import org.apache.wss4j.stax.securityEvent.NoSecuritySecurityEvent;
 import org.apache.wss4j.stax.securityEvent.OperationSecurityEvent;
+import org.apache.wss4j.stax.securityEvent.UsernameTokenSecurityEvent;
 import org.apache.wss4j.stax.securityEvent.WSSecurityEventConstants;
 import org.apache.xml.security.exceptions.XMLSecurityException;
+import org.apache.xml.security.stax.securityEvent.AlgorithmSuiteSecurityEvent;
 import org.apache.xml.security.stax.securityEvent.SecurityEvent;
 import org.apache.xml.security.stax.securityEvent.SecurityEventConstants;
 import org.apache.xml.security.stax.securityEvent.SecurityEventListener;
@@ -156,6 +158,8 @@ public class PolicyEnforcer implements 
SecurityEventListener {
     private boolean faultOccurred;
     private final PolicyAsserter policyAsserter;
     private boolean soap12;
+    private boolean usernameTokenNoPasswordRelaxedForAllOperations;
+    private boolean rsa15KeyTransportRelaxedForAllOperations;
 
     public PolicyEnforcer(List<OperationPolicy> operationPolicies, String 
soapAction, boolean initiator,
                           String actorOrRole, int attachmentCount, 
PolicyAsserter policyAsserter, boolean soap12
@@ -892,6 +896,11 @@ public class PolicyEnforcer implements 
SecurityEventListener {
                         new IllegalArgumentException(message));
             }
 
+            //The operation is known now, so an engine default relaxed on the 
strength of
+            //the whole policy set can be reimposed where this operation's 
policy does not
+            //ask for it.
+            verifyRelaxedEngineDefaults();
+
             try {
                 Iterator<SecurityEvent> securityEventIterator = 
securityEventQueue.descendingIterator();
                 while (securityEventIterator.hasNext()) {
@@ -923,18 +932,25 @@ public class PolicyEnforcer implements 
SecurityEventListener {
     }
 
     /**
-     * Returns true if any configured operation policy contains a 
UsernameToken assertion
-     * that explicitly allows password-less tokens (sp:NoPassword). Used to 
decide whether
-     * the engine's hardened default (rejecting password-less UsernameTokens) 
may be
-     * relaxed in policy mode.
+     * Returns true if the policy that governs this message contains a 
UsernameToken
+     * assertion that explicitly allows password-less tokens (sp:NoPassword). 
Used to
+     * decide whether the engine's hardened default (rejecting password-less
+     * UsernameTokens) may be relaxed in policy mode.
+     *
+     * This is asked while the security header is being read, so the operation 
is known
+     * only where SOAPAction already selected its policy. Failing that the 
question can be
+     * answered across the configured operations and no more, which relaxes 
the default for
+     * a message that may turn out to invoke an operation whose own policy 
does not allow
+     * it. Record that, so that verifyRelaxedEngineDefaults() can reimpose the 
default once
+     * the operation is known.
      */
     public boolean isUsernameTokenNoPasswordAllowedByPolicy() {
+        if (effectivePolicy != null) {
+            return allowsUsernameTokenNoPassword(effectivePolicy);
+        }
         for (OperationPolicy operationPolicy : operationPolicies) {
-            Policy policy = operationPolicy.getPolicy();
-            if (policy != null && policyContains(policy,
-                assertion -> assertion instanceof UsernameToken
-                    && ((UsernameToken)assertion).getPasswordType()
-                        == UsernameToken.PasswordType.NoPassword)) {
+            if (allowsUsernameTokenNoPassword(operationPolicy)) {
+                usernameTokenNoPasswordRelaxedForAllOperations = true;
                 return true;
             }
         }
@@ -942,28 +958,92 @@ public class PolicyEnforcer implements 
SecurityEventListener {
     }
 
     /**
-     * Returns true if any configured operation policy contains an 
AlgorithmSuite whose
-     * asymmetric key wrap is RSA v1.5. Used to decide whether the engine's 
hardened
-     * default (rejecting rsa-1_5 key transport) may be relaxed in policy mode.
+     * Returns true if the policy that governs this message contains an 
AlgorithmSuite whose
+     * asymmetric key wrap is RSA v1.5. Used to decide whether the engine's 
hardened default
+     * (rejecting rsa-1_5 key transport) may be relaxed in policy mode. Scoped 
to the
+     * operation, and recorded when it cannot be, exactly as above.
      */
     public boolean isRSA15KeyTransportAllowedByPolicy() {
+        if (effectivePolicy != null) {
+            return allowsRSA15KeyTransport(effectivePolicy);
+        }
         for (OperationPolicy operationPolicy : operationPolicies) {
-            Policy policy = operationPolicy.getPolicy();
-            if (policy != null && policyContains(policy, assertion -> {
-                if (!(assertion instanceof AlgorithmSuite)) {
-                    return false;
-                }
-                AlgorithmSuite.AlgorithmSuiteType algorithmSuiteType =
-                    ((AlgorithmSuite)assertion).getAlgorithmSuiteType();
-                return algorithmSuiteType != null
-                    && 
SPConstants.KW_RSA15.equals(algorithmSuiteType.getAsymmetricKeyWrap());
-            })) {
+            if (allowsRSA15KeyTransport(operationPolicy)) {
+                rsa15KeyTransportRelaxedForAllOperations = true;
                 return true;
             }
         }
         return false;
     }
 
+    private static boolean allowsUsernameTokenNoPassword(OperationPolicy 
operationPolicy) {
+        Policy policy = operationPolicy.getPolicy();
+        return policy != null && policyContains(policy,
+            assertion -> assertion instanceof UsernameToken
+                && ((UsernameToken)assertion).getPasswordType()
+                    == UsernameToken.PasswordType.NoPassword);
+    }
+
+    private static boolean allowsRSA15KeyTransport(OperationPolicy 
operationPolicy) {
+        Policy policy = operationPolicy.getPolicy();
+        return policy != null && policyContains(policy, assertion -> {
+            if (!(assertion instanceof AlgorithmSuite)) {
+                return false;
+            }
+            AlgorithmSuite.AlgorithmSuiteType algorithmSuiteType =
+                ((AlgorithmSuite)assertion).getAlgorithmSuiteType();
+            return algorithmSuiteType != null
+                && 
SPConstants.KW_RSA15.equals(algorithmSuiteType.getAsymmetricKeyWrap());
+        });
+    }
+
+    /**
+     * An engine default that was relaxed on the strength of the whole set of 
operation
+     * policies - because the operation was not yet known when the security 
header was read
+     * - must still hold for the operation the message turned out to invoke. 
Otherwise one
+     * operation that asks for sp:NoPassword or for rsa-1_5 lowers the 
engine's floor for
+     * every other operation of the endpoint, and whether that is caught 
depends on whether
+     * the effective policy happens to carry an assertion that rejects what 
was accepted: a
+     * password-less UsernameToken is not examined at all by a policy that 
names no
+     * UsernameToken.
+     */
+    private void verifyRelaxedEngineDefaults() throws WSSecurityException {
+        if (usernameTokenNoPasswordRelaxedForAllOperations
+            && !allowsUsernameTokenNoPassword(effectivePolicy)) {
+            for (SecurityEvent securityEvent : securityEventQueue) {
+                if (securityEvent instanceof UsernameTokenSecurityEvent
+                    && 
((UsernameTokenSecurityEvent)securityEvent).getSecurityToken() != null
+                    && WSSConstants.UsernameTokenPasswordType.PASSWORD_NONE
+                        == 
((UsernameTokenSecurityEvent)securityEvent).getUsernameTokenPasswordType()) {
+                    rejectRelaxedEngineDefault("a UsernameToken with no 
password");
+                }
+            }
+        }
+        if (rsa15KeyTransportRelaxedForAllOperations
+            && !allowsRSA15KeyTransport(effectivePolicy)) {
+            for (SecurityEvent securityEvent : securityEventQueue) {
+                if (securityEvent instanceof AlgorithmSuiteSecurityEvent) {
+                    AlgorithmSuiteSecurityEvent algorithmSuiteSecurityEvent =
+                        (AlgorithmSuiteSecurityEvent)securityEvent;
+                    if 
(WSSConstants.Asym_Key_Wrap.equals(algorithmSuiteSecurityEvent.getAlgorithmUsage())
+                        && 
WSSConstants.NS_XENC_RSA15.equals(algorithmSuiteSecurityEvent.getAlgorithmURI()))
 {
+                        rejectRelaxedEngineDefault("rsa-1_5 key transport");
+                    }
+                }
+            }
+        }
+    }
+
+    private void rejectRelaxedEngineDefault(String what) throws 
WSSecurityException {
+        String message = "The message uses " + what + ", which the policy for 
operation "
+            + effectivePolicy.getOperationName() + " does not allow";
+        LOG.warn("{}; rejecting the message", message);
+        securityEventQueue.clear();
+        throw new WSSecurityException(
+                WSSecurityException.ErrorCode.INVALID_SECURITY,
+                new IllegalArgumentException(message));
+    }
+
     private static boolean policyContains(PolicyComponent policyComponent, 
Predicate<Assertion> predicate) {
         if (policyComponent instanceof PolicyOperator) {
             for (PolicyComponent childComponent
diff --git 
a/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/enforcer/PolicyInputProcessor.java
 
b/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/enforcer/PolicyInputProcessor.java
index 78a4d3ef2..90d7264fd 100644
--- 
a/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/enforcer/PolicyInputProcessor.java
+++ 
b/ws-security-policy-stax/src/main/java/org/apache/wss4j/policy/stax/enforcer/PolicyInputProcessor.java
@@ -254,11 +254,23 @@ public class PolicyInputProcessor extends 
AbstractInputProcessor {
             // unconditionally, which silently reversed both defaults even 
when the
             // configured policy contained no assertion that re-imposes the 
check. Only
             // relax an engine default when the policy actually covers it.
-            if (policyEnforcer.isRSA15KeyTransportAllowedByPolicy()) {
+            // Where the caller has already relaxed a default itself there is 
nothing to
+            // grant, and asking would arm a re-check against a policy the 
caller has
+            // deliberately overruled, so leave that case alone. The 
properties are
+            // optional on this processor - a caller may construct it with 
none - and then
+            // the caller has relaxed nothing.
+            XMLSecurityProperties properties = getSecurityProperties();
+            WSSSecurityProperties securityProperties =
+                properties instanceof WSSSecurityProperties ? 
(WSSSecurityProperties) properties : null;
+            boolean callerAllowsRSA15 =
+                securityProperties != null && 
securityProperties.isAllowRSA15KeyTransportAlgorithm();
+            boolean callerAllowsNoPassword =
+                securityProperties != null && 
securityProperties.isAllowUsernameTokenNoPassword();
+            if (!callerAllowsRSA15 && 
policyEnforcer.isRSA15KeyTransportAllowedByPolicy()) {
                 inputProcessorChain.getSecurityContext().put(
                     WSSConstants.PROP_ALLOW_RSA15_KEYTRANSPORT_ALGORITHM, 
Boolean.TRUE);
             }
-            if (policyEnforcer.isUsernameTokenNoPasswordAllowedByPolicy()) {
+            if (!callerAllowsNoPassword && 
policyEnforcer.isUsernameTokenNoPasswordAllowedByPolicy()) {
                 inputProcessorChain.getSecurityContext().put(
                     WSSConstants.PROP_ALLOW_USERNAMETOKEN_NOPASSWORD, 
Boolean.TRUE.toString());
             }
diff --git 
a/ws-security-policy-stax/src/test/java/org/apache/wss4j/policy/stax/test/ScopedEngineDefaultsTest.java
 
b/ws-security-policy-stax/src/test/java/org/apache/wss4j/policy/stax/test/ScopedEngineDefaultsTest.java
new file mode 100644
index 000000000..b97605567
--- /dev/null
+++ 
b/ws-security-policy-stax/src/test/java/org/apache/wss4j/policy/stax/test/ScopedEngineDefaultsTest.java
@@ -0,0 +1,155 @@
+/**
+ * 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.policy.stax.test;
+
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+
+import javax.xml.namespace.QName;
+
+import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.common.util.DateUtil;
+import org.apache.wss4j.policy.stax.enforcer.PolicyEnforcer;
+import org.apache.wss4j.policy.stax.enforcer.PolicyEnforcerFactory;
+import org.apache.wss4j.stax.ext.WSSConstants;
+import org.apache.wss4j.stax.impl.securityToken.UsernameSecurityTokenImpl;
+import org.apache.wss4j.stax.securityEvent.OperationSecurityEvent;
+import org.apache.wss4j.stax.securityEvent.UsernameTokenSecurityEvent;
+import org.apache.wss4j.stax.securityToken.WSSecurityTokenConstants;
+import org.apache.xml.security.exceptions.XMLSecurityException;
+import org.apache.xml.security.stax.impl.util.IDGenerator;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * The engine's hardened defaults - rejecting password-less UsernameTokens and 
rsa-1_5 key
+ * transport - are relaxed in policy mode so that the corresponding policy 
assertions can
+ * take over. The relaxation belongs to the operation whose policy asks for 
it, not to every
+ * operation of the endpoint.
+ *
+ * The WSDL behind these tests has two operations: one asks for sp:NoPassword, 
the other
+ * names no UsernameToken at all, so nothing in its own policy would reject a 
password-less
+ * token that the engine has already accepted.
+ */
+public class ScopedEngineDefaultsTest extends AbstractPolicyTestBase {
+
+    private static final String NAMESPACE = 
"http://www.example.net/MixedPolicyService";;
+    private static final QName NO_PASSWORD_OPERATION = new QName(NAMESPACE, 
"noPasswordOperation");
+    private static final QName PASSWORD_OPERATION = new QName(NAMESPACE, 
"passwordOperation");
+
+    /**
+     * Where SOAPAction has already selected the operation, only that 
operation's policy
+     * decides. The operation that asks for no password gets the relaxation; 
the one that
+     * does not, does not.
+     */
+    @Test
+    public void testRelaxationIsScopedToTheOperationSelectedBySOAPAction() 
throws Exception {
+        
assertTrue(newPolicyEnforcer("noPasswordOperationAction").isUsernameTokenNoPasswordAllowedByPolicy());
+        
assertFalse(newPolicyEnforcer("passwordOperationAction").isUsernameTokenNoPasswordAllowedByPolicy());
+    }
+
+    /**
+     * Without a SOAPAction the operation is not known while the security 
header is being
+     * read, so the question can only be answered across every configured 
operation. The
+     * engine default is still relaxed, as before, or a deployment whose 
operation cannot be
+     * determined that early would stop working.
+     */
+    @Test
+    public void testRelaxationStillGrantedWhenTheOperationIsNotYetKnown() 
throws Exception {
+        
assertTrue(newPolicyEnforcer("").isUsernameTokenNoPasswordAllowedByPolicy());
+    }
+
+    /**
+     * ...but once the operation turns out to be the one whose policy says 
nothing about
+     * UsernameTokens, a password-less token accepted under that relaxation is 
rejected.
+     */
+    @Test
+    public void 
testPasswordlessTokenRejectedForAnOperationThatDoesNotAllowIt() throws 
Exception {
+        PolicyEnforcer policyEnforcer = newPolicyEnforcer("");
+        assertTrue(policyEnforcer.isUsernameTokenNoPasswordAllowedByPolicy());
+        policyEnforcer.registerSecurityEvent(passwordlessUsernameTokenEvent());
+
+        OperationSecurityEvent operationSecurityEvent = new 
OperationSecurityEvent();
+        operationSecurityEvent.setOperation(PASSWORD_OPERATION);
+
+        WSSecurityException ex = assertThrows(WSSecurityException.class,
+                () -> 
policyEnforcer.registerSecurityEvent(operationSecurityEvent));
+
+        assertEquals("The message uses a UsernameToken with no password, which 
the policy for "
+                        + "operation " + PASSWORD_OPERATION + " does not 
allow",
+                ex.getCause().getMessage());
+        assertEquals(WSSecurityException.INVALID_SECURITY, ex.getFaultCode());
+    }
+
+    /**
+     * The same message is accepted for the operation whose policy does ask for
+     * sp:NoPassword.
+     */
+    @Test
+    public void testPasswordlessTokenAcceptedForTheOperationThatAllowsIt() 
throws Exception {
+        PolicyEnforcer policyEnforcer = newPolicyEnforcer("");
+        assertTrue(policyEnforcer.isUsernameTokenNoPasswordAllowedByPolicy());
+        policyEnforcer.registerSecurityEvent(passwordlessUsernameTokenEvent());
+
+        OperationSecurityEvent operationSecurityEvent = new 
OperationSecurityEvent();
+        operationSecurityEvent.setOperation(NO_PASSWORD_OPERATION);
+
+        policyEnforcer.registerSecurityEvent(operationSecurityEvent);
+    }
+
+    /**
+     * A message that carries no password-less token is unaffected, even 
though the
+     * relaxation was granted across the endpoint.
+     */
+    @Test
+    public void testOperationWithoutAPasswordlessTokenIsUnaffected() throws 
Exception {
+        PolicyEnforcer policyEnforcer = newPolicyEnforcer("");
+        assertTrue(policyEnforcer.isUsernameTokenNoPasswordAllowedByPolicy());
+
+        OperationSecurityEvent operationSecurityEvent = new 
OperationSecurityEvent();
+        operationSecurityEvent.setOperation(PASSWORD_OPERATION);
+
+        policyEnforcer.registerSecurityEvent(operationSecurityEvent);
+    }
+
+    private PolicyEnforcer newPolicyEnforcer(String soapAction) throws 
Exception {
+        PolicyEnforcerFactory policyEnforcerFactory = 
PolicyEnforcerFactory.newInstance(
+                
this.getClass().getClassLoader().getResource("testdata/wsdl/mixedPasswordPolicies.wsdl"));
+        return policyEnforcerFactory.newPolicyEnforcer(soapAction, false, 
null, 0, false);
+    }
+
+    private UsernameTokenSecurityEvent passwordlessUsernameTokenEvent() throws 
XMLSecurityException {
+        UsernameTokenSecurityEvent usernameTokenSecurityEvent = new 
UsernameTokenSecurityEvent();
+        
usernameTokenSecurityEvent.setUsernameTokenProfile(WSSConstants.NS_USERNAMETOKEN_PROFILE11);
+        ZonedDateTime now = ZonedDateTime.now(ZoneOffset.UTC);
+        String created = DateUtil.getDateTimeFormatter(true).format(now);
+        UsernameSecurityTokenImpl usernameSecurityToken = new 
UsernameSecurityTokenImpl(
+                WSSConstants.UsernameTokenPasswordType.PASSWORD_NONE,
+                "username", null, created, null, new byte[10], 10L,
+                null, IDGenerator.generateID(null),
+                
WSSecurityTokenConstants.KEYIDENTIFIER_SECURITY_TOKEN_DIRECT_REFERENCE);
+        
usernameSecurityToken.addTokenUsage(WSSecurityTokenConstants.TOKENUSAGE_SUPPORTING_TOKENS);
+        usernameTokenSecurityEvent.setSecurityToken(usernameSecurityToken);
+        return usernameTokenSecurityEvent;
+    }
+}
diff --git 
a/ws-security-policy-stax/src/test/resources/testdata/wsdl/mixedPasswordPolicies.wsdl
 
b/ws-security-policy-stax/src/test/resources/testdata/wsdl/mixedPasswordPolicies.wsdl
new file mode 100644
index 000000000..015ceb6ac
--- /dev/null
+++ 
b/ws-security-policy-stax/src/test/resources/testdata/wsdl/mixedPasswordPolicies.wsdl
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<wsdl:definitions
+        name="MixedPolicyService"
+        targetNamespace="http://www.example.net/MixedPolicyService";
+        xmlns:tns="http://www.example.net/MixedPolicyService";
+        xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy";
+        xmlns:sp="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702";
+        
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd";
+        xmlns:xs="http://www.w3.org/2001/XMLSchema";
+        xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/";
+        xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/";
+        >
+
+    <!-- Two operations of one endpoint, only one of which asks for 
password-less
+         UsernameTokens. The other names no UsernameToken at all, so nothing 
in its own
+         policy would reject one that the engine has already accepted. -->
+
+    <wsdl:types>
+        <xs:schema targetNamespace="http://www.example.net/MixedPolicyService";
+                   xmlns:xs="http://www.w3.org/2001/XMLSchema";>
+            <xs:element name="noPasswordOperation" type="xs:string"/>
+            <xs:element name="passwordOperation" type="xs:string"/>
+        </xs:schema>
+    </wsdl:types>
+
+    <wsp:Policy wsu:Id="NoPasswordPolicy">
+        <wsp:ExactlyOne>
+            <wsp:All>
+                <sp:SupportingTokens>
+                    <wsp:Policy>
+                        <sp:UsernameToken>
+                            <wsp:Policy>
+                                <sp:NoPassword/>
+                            </wsp:Policy>
+                        </sp:UsernameToken>
+                    </wsp:Policy>
+                </sp:SupportingTokens>
+            </wsp:All>
+        </wsp:ExactlyOne>
+    </wsp:Policy>
+
+    <wsdl:message name="noPasswordOperationRequest">
+        <wsdl:part name="parameters" element="tns:noPasswordOperation"/>
+    </wsdl:message>
+    <wsdl:message name="passwordOperationRequest">
+        <wsdl:part name="parameters" element="tns:passwordOperation"/>
+    </wsdl:message>
+
+    <wsdl:portType name="MixedPolicyPort">
+        <wsdl:operation name="noPasswordOperation">
+            <wsdl:input message="tns:noPasswordOperationRequest"/>
+        </wsdl:operation>
+        <wsdl:operation name="passwordOperation">
+            <wsdl:input message="tns:passwordOperationRequest"/>
+        </wsdl:operation>
+    </wsdl:portType>
+
+    <wsdl:binding name="MixedPolicySOAPBinding" type="tns:MixedPolicyPort">
+        <soap:binding transport="http://schemas.xmlsoap.org/soap/http"; 
style="document"/>
+        <wsdl:operation name="noPasswordOperation">
+            <wsp:PolicyReference URI="#NoPasswordPolicy"/>
+            <soap:operation soapAction="noPasswordOperationAction" 
style="document"/>
+            <wsdl:input>
+                <soap:body use="literal"/>
+            </wsdl:input>
+        </wsdl:operation>
+        <wsdl:operation name="passwordOperation">
+            <soap:operation soapAction="passwordOperationAction" 
style="document"/>
+            <wsdl:input>
+                <soap:body use="literal"/>
+            </wsdl:input>
+        </wsdl:operation>
+    </wsdl:binding>
+
+    <wsdl:service name="MixedPolicyService">
+        <wsdl:port name="MixedPolicy" binding="tns:MixedPolicySOAPBinding">
+            <soap:address location="http://localhost:8080/MixedPolicyService"/>
+        </wsdl:port>
+    </wsdl:service>
+</wsdl:definitions>

Reply via email to