This is an automated email from the ASF dual-hosted git repository. coheigea pushed a commit to branch coheigea/CXF-9167 in repository https://gitbox.apache.org/repos/asf/cxf.git
commit d6714384c8c192cb656b9119e84088f435a0bd53 Author: Colm O hEigeartaigh <[email protected]> AuthorDate: Wed Feb 4 10:15:48 2026 +0000 CXF-9167 - Enable Custom Processor Injection in PolicyBasedWSS4JInInterceptor --- .../wss4j/PolicyBasedWSS4JInInterceptor.java | 5 ++ .../cxf/ws/security/wss4j/WSS4JInInterceptor.java | 27 +++++---- .../systest/ws/ut/CustomUTPasswordCallback.java | 65 ++++++++++++++++++++++ .../cxf/systest/ws/ut/CustomUTProcessor.java | 43 ++++++++++++++ .../cxf/systest/ws/ut/UsernameTokenPolicyTest.java | 30 ++++++++++ .../apache/cxf/systest/ws/ut/DoubleItUtPolicy.wsdl | 3 + .../org/apache/cxf/systest/ws/ut/policy-client.xml | 11 ++++ .../org/apache/cxf/systest/ws/ut/policy-server.xml | 20 +++++++ 8 files changed, 192 insertions(+), 12 deletions(-) diff --git a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/PolicyBasedWSS4JInInterceptor.java b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/PolicyBasedWSS4JInInterceptor.java index ca8ada8fae..17e7e885c3 100644 --- a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/PolicyBasedWSS4JInInterceptor.java +++ b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/PolicyBasedWSS4JInInterceptor.java @@ -556,6 +556,11 @@ public class PolicyBasedWSS4JInInterceptor extends WSS4JInInterceptor { } message.put(ConfigurationConstants.ACTION, action.trim()); + + // Set any custom WSS4J Processor instances that are configured + final Map<QName, Object> processorMap = CastUtils.cast( + (Map<?, ?>)SecurityUtils.getSecurityPropertyValue(PROCESSOR_MAP, message)); + configureCustomProcessors(data.getWssConfig(), processorMap); } } diff --git a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/WSS4JInInterceptor.java b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/WSS4JInInterceptor.java index e6c26001aa..13c8bf902a 100644 --- a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/WSS4JInInterceptor.java +++ b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/WSS4JInInterceptor.java @@ -133,18 +133,7 @@ public class WSS4JInInterceptor extends AbstractWSS4JInterceptor { // Set any custom WSS4J Processor instances that are configured final Map<QName, Object> processorMap = CastUtils.cast( (Map<?, ?>)properties.get(PROCESSOR_MAP)); - if (processorMap != null) { - for (Map.Entry<QName, Object> entry : processorMap.entrySet()) { - Object val = entry.getValue(); - if (val instanceof Class<?>) { - config.setProcessor(entry.getKey(), (Class<?>)val); - } else if (val instanceof Processor) { - config.setProcessor(entry.getKey(), (Processor)val); - } else if (val == null) { - config.setProcessor(entry.getKey(), (Class<?>)null); - } - } - } + configureCustomProcessors(config, processorMap); // Set any custom WSS4J Validator instances that are configured Map<QName, Object> validatorMap = CastUtils.cast( @@ -729,4 +718,18 @@ public class WSS4JInInterceptor extends AbstractWSS4JInterceptor { return WSS4JUtils.getReplayCache(message, booleanKey, instanceKey); } + protected void configureCustomProcessors(WSSConfig config, final Map<QName, Object> processorMap) { + if (processorMap != null) { + for (Map.Entry<QName, Object> entry : processorMap.entrySet()) { + Object val = entry.getValue(); + if (val instanceof Class<?>) { + config.setProcessor(entry.getKey(), (Class<?>)val); + } else if (val instanceof Processor) { + config.setProcessor(entry.getKey(), (Processor)val); + } else if (val == null) { + config.setProcessor(entry.getKey(), (Class<?>)null); + } + } + } + } } diff --git a/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/ut/CustomUTPasswordCallback.java b/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/ut/CustomUTPasswordCallback.java new file mode 100644 index 0000000000..67d6eccbe8 --- /dev/null +++ b/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/ut/CustomUTPasswordCallback.java @@ -0,0 +1,65 @@ +/** + * 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.cxf.systest.ws.ut; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import org.apache.wss4j.common.ext.WSPasswordCallback; + +/** + * A CallbackHandler implementation used to test custom Processors. + */ +public class CustomUTPasswordCallback implements CallbackHandler { + + private Map<String, String> passwords = + new HashMap<>(); + + public CustomUTPasswordCallback() { + passwords.put("Alice", "ecilAAlice"); + } + + /** + * Here, we attempt to get the password from the private + * alias/passwords map. + */ + public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { + for (int i = 0; i < callbacks.length; i++) { + WSPasswordCallback pc = (WSPasswordCallback)callbacks[i]; + + String pass = passwords.get(pc.getIdentifier()); + if (pass != null) { + pc.setPassword(pass); + return; + } + } + } + + /** + * Add an alias/password pair to the callback mechanism. + */ + public void setAliasPassword(String alias, String password) { + passwords.put(alias, password); + } +} diff --git a/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/ut/CustomUTProcessor.java b/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/ut/CustomUTProcessor.java new file mode 100644 index 0000000000..ef322cb829 --- /dev/null +++ b/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/ut/CustomUTProcessor.java @@ -0,0 +1,43 @@ +/** + * 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.cxf.systest.ws.ut; + +import java.util.List; + +import org.w3c.dom.Element; + +import org.apache.wss4j.common.ext.WSSecurityException; +import org.apache.wss4j.dom.engine.WSSecurityEngineResult; +import org.apache.wss4j.dom.handler.RequestData; +import org.apache.wss4j.dom.processor.Processor; +import org.apache.wss4j.dom.processor.UsernameTokenProcessor; + +/** + * A custom Processor that overrides the default CallbackHandler to use a CustomUTPasswordCallback + */ +public class CustomUTProcessor implements Processor { + + @Override + public List<WSSecurityEngineResult> handleToken(Element elem, RequestData request) throws WSSecurityException { + request.setCallbackHandler(new CustomUTPasswordCallback()); + UsernameTokenProcessor processor = new UsernameTokenProcessor(); + return processor.handleToken(elem, request); + } +} diff --git a/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/ut/UsernameTokenPolicyTest.java b/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/ut/UsernameTokenPolicyTest.java index f990946bcd..0f16c5c435 100644 --- a/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/ut/UsernameTokenPolicyTest.java +++ b/systests/ws-security/src/test/java/org/apache/cxf/systest/ws/ut/UsernameTokenPolicyTest.java @@ -406,5 +406,35 @@ public class UsernameTokenPolicyTest extends AbstractBusClientServerTestBase { } + // https://issues.apache.org/jira/browse/CXF-9167 + // Here we're sending a UsernameToken with a password unknown by the default CallbackHandler on the server side, + // but we are overriding the UsernameToken processor to use a CallbackHandler that knows the password. + @org.junit.Test + public void testSupportingTokenCustomProcessor() throws Exception { + + if (test.getPort().equals(STAX_PORT)) { + // We don't support custom processors with streaming for now + return; + } + + SpringBusFactory bf = new SpringBusFactory(); + URL busFile = UsernameTokenPolicyTest.class.getResource("policy-client.xml"); + + Bus bus = bf.createBus(busFile.toString()); + BusFactory.setDefaultBus(bus); + BusFactory.setThreadDefaultBus(bus); + + URL wsdl = UsernameTokenPolicyTest.class.getResource("DoubleItUtPolicy.wsdl"); + Service service = Service.create(wsdl, SERVICE_QNAME); + QName portQName = new QName(NAMESPACE, "DoubleItSupportingTokenPort3"); + DoubleItPortType port = + service.getPort(portQName, DoubleItPortType.class); + updateAddressPort(port, test.getPort()); + + assertEquals(50, port.doubleIt(25)); + + ((java.io.Closeable)port).close(); + bus.shutdown(true); + } } diff --git a/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/ut/DoubleItUtPolicy.wsdl b/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/ut/DoubleItUtPolicy.wsdl index 9ae032212d..7811d02939 100644 --- a/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/ut/DoubleItUtPolicy.wsdl +++ b/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/ut/DoubleItUtPolicy.wsdl @@ -41,6 +41,9 @@ <wsdl:port name="DoubleItSupportingTokenPort2" binding="tns:DoubleItInlinePolicyBinding"> <soap:address location="https://localhost:9009/DoubleItSupportingToken2"/> </wsdl:port> + <wsdl:port name="DoubleItSupportingTokenPort3" binding="tns:DoubleItInlinePolicyBinding"> + <soap:address location="https://localhost:9009/DoubleItSupportingToken3"/> + </wsdl:port> <wsdl:port name="DoubleItPlaintextPort" binding="tns:DoubleItInlinePolicyBinding"> <soap:address location="https://localhost:9009/DoubleItPlaintext"/> </wsdl:port> diff --git a/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/ut/policy-client.xml b/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/ut/policy-client.xml index f9b2d4337c..c6d710b093 100644 --- a/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/ut/policy-client.xml +++ b/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/ut/policy-client.xml @@ -60,6 +60,17 @@ </p:policies> </jaxws:features> </jaxws:client> + <jaxws:client name="{http://www.example.org/contract/DoubleIt}DoubleItSupportingTokenPort3" createdFromAPI="true"> + <jaxws:properties> + <entry key="security.username" value="Alice"/> + <entry key="security.callback-handler" value="org.apache.cxf.systest.ws.ut.CustomUTPasswordCallback"/> + </jaxws:properties> + <jaxws:features> + <p:policies> + <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy" URI="classpath:/org/apache/cxf/systest/ws/ut/supp-token-policy.xml"/> + </p:policies> + </jaxws:features> + </jaxws:client> <jaxws:client name="{http://www.example.org/contract/DoubleIt}DoubleItPlaintextPort" createdFromAPI="true"> <jaxws:properties> <entry key="security.username" value="Alice"/> diff --git a/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/ut/policy-server.xml b/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/ut/policy-server.xml index 1606e002b6..231480e7d3 100644 --- a/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/ut/policy-server.xml +++ b/systests/ws-security/src/test/resources/org/apache/cxf/systest/ws/ut/policy-server.xml @@ -70,6 +70,26 @@ </p:policies> </jaxws:features> </jaxws:endpoint> + <!-- Add a java QName for a WS-Security UsernameToken --> + <bean id="wsse-username-token" class="javax.xml.namespace.QName"> + <constructor-arg value="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"/> + <constructor-arg value="UsernameToken"/> + </bean> + <bean id="custom-ut-processor" class="org.apache.cxf.systest.ws.ut.CustomUTProcessor"/> + <jaxws:endpoint xmlns:s="http://www.example.org/contract/DoubleIt" id="SupportingToken3" address="https://localhost:${testutil.ports.PolicyServer}/DoubleItSupportingToken3" serviceName="s:DoubleItService" endpointName="s:DoubleItSupportingTokenPort3" implementor="org.apache.cxf.systest.ws.common.DoubleItPortTypeImpl" wsdlLocation="org/apache/cxf/systest/ws/ut/DoubleItUtPolicy.wsdl" depends-on="tls-settings"> + <jaxws:properties> + <entry key="wss4j.processor.map"> + <map> + <entry key-ref="wsse-username-token" value-ref="custom-ut-processor"/> + </map> + </entry> + </jaxws:properties> + <jaxws:features> + <p:policies> + <wsp:PolicyReference xmlns:wsp="http://www.w3.org/ns/ws-policy" URI="classpath:/org/apache/cxf/systest/ws/ut/supp-token-policy.xml"/> + </p:policies> + </jaxws:features> + </jaxws:endpoint> <jaxws:endpoint xmlns:s="http://www.example.org/contract/DoubleIt" id="PlainText" address="https://localhost:${testutil.ports.PolicyServer}/DoubleItPlaintext" serviceName="s:DoubleItService" endpointName="s:DoubleItPlaintextPort" implementor="org.apache.cxf.systest.ws.common.DoubleItPortTypeImpl" wsdlLocation="org/apache/cxf/systest/ws/ut/DoubleItUtPolicy.wsdl" depends-on="tls-settings"> <jaxws:properties> <entry key="security.callback-handler" value="org.apache.cxf.systest.ws.common.UTPasswordCallback"/>
