You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by co...@apache.org on 2019/01/09 11:55:19 UTC

[cxf] branch master updated: CXF-7938 / CXF-7939 - Support the WSS4J "validatorMap" configuration constant + Support omitting the "action" string when "ignoreActions" is true in WSS4JInInterceptor

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

coheigea pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cxf.git


The following commit(s) were added to refs/heads/master by this push:
     new 976ecb5  CXF-7938 / CXF-7939 - Support the WSS4J "validatorMap" configuration constant + Support omitting the "action" string when "ignoreActions" is true in WSS4JInInterceptor
976ecb5 is described below

commit 976ecb5f43bd873d01e07078194636a99e812906
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Wed Jan 9 11:54:14 2019 +0000

    CXF-7938 / CXF-7939 - Support the WSS4J "validatorMap" configuration constant + Support omitting the "action" string when "ignoreActions" is true in WSS4JInInterceptor
---
 ...ractUsernameTokenAuthenticatingInterceptor.java | 13 ++--
 .../cxf/ws/security/wss4j/WSS4JInInterceptor.java  | 86 +++++++++++-----------
 .../common/KerberosClientPasswordCallback.java     | 25 +++++++
 .../kerberos/wssec/kerberos/KerberosTokenTest.java | 22 ++++++
 .../kerberos/wssec/kerberos/DoubleItKerberos.wsdl  | 18 +++++
 .../cxf/systest/kerberos/wssec/kerberos/client.xml | 13 ++++
 .../cxf/systest/kerberos/wssec/kerberos/server.xml | 24 +++++-
 7 files changed, 152 insertions(+), 49 deletions(-)

diff --git a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/AbstractUsernameTokenAuthenticatingInterceptor.java b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/AbstractUsernameTokenAuthenticatingInterceptor.java
index 0508dc2..e0bed7b 100644
--- a/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/AbstractUsernameTokenAuthenticatingInterceptor.java
+++ b/rt/ws/security/src/main/java/org/apache/cxf/ws/security/wss4j/AbstractUsernameTokenAuthenticatingInterceptor.java
@@ -26,7 +26,6 @@ import java.util.Map;
 import java.util.logging.Logger;
 
 import javax.security.auth.Subject;
-import javax.xml.namespace.QName;
 import javax.xml.soap.SOAPException;
 import javax.xml.stream.XMLStreamException;
 
@@ -44,12 +43,12 @@ import org.apache.cxf.phase.PhaseInterceptorChain;
 import org.apache.cxf.security.SecurityContext;
 import org.apache.wss4j.common.ext.WSSecurityException;
 import org.apache.wss4j.dom.WSConstants;
+import org.apache.wss4j.dom.engine.WSSConfig;
 import org.apache.wss4j.dom.engine.WSSecurityEngine;
 import org.apache.wss4j.dom.handler.RequestData;
 import org.apache.wss4j.dom.handler.WSHandlerConstants;
 import org.apache.wss4j.dom.handler.WSHandlerResult;
 import org.apache.wss4j.dom.validate.UsernameTokenValidator;
-import org.apache.wss4j.dom.validate.Validator;
 
 
 /**
@@ -197,11 +196,11 @@ public abstract class AbstractUsernameTokenAuthenticatingInterceptor extends WSS
 
     @Override
     protected WSSecurityEngine getSecurityEngine(boolean utNoCallbacks) {
-        Map<QName, Object> profiles = new HashMap<>(1);
-
-        Validator validator = new CustomValidator();
-        profiles.put(WSConstants.USERNAME_TOKEN, validator);
-        return createSecurityEngine(profiles);
+        WSSConfig config = WSSConfig.getNewInstance();
+        config.setValidator(WSConstants.USERNAME_TOKEN, new CustomValidator());
+        WSSecurityEngine ret = new WSSecurityEngine();
+        ret.setWssConfig(config);
+        return ret;
     }
 
     protected class CustomValidator extends UsernameTokenValidator {
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 8c70f03..bfb7b9c 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
@@ -22,7 +22,6 @@ import java.lang.reflect.Method;
 import java.security.Provider;
 import java.security.cert.Certificate;
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
@@ -121,24 +120,55 @@ public class WSS4JInInterceptor extends AbstractWSS4JInterceptor {
     public WSS4JInInterceptor(Map<String, Object> properties) {
         this();
         setProperties(properties);
+        WSSConfig config = WSSConfig.getNewInstance();
+
+        // Set any custom WSS4J Processor instances that are configured
         final Map<QName, Object> processorMap = CastUtils.cast(
             (Map<?, ?>)properties.get(PROCESSOR_MAP));
-        final Map<QName, Object> validatorMap = CastUtils.cast(
-            (Map<?, ?>)properties.get(VALIDATOR_MAP));
-
         if (processorMap != null) {
-            if (validatorMap != null) {
-                processorMap.putAll(validatorMap);
+            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);
+                }
             }
-            secEngineOverride = createSecurityEngine(processorMap);
-        } else if (validatorMap != null) {
-            secEngineOverride = createSecurityEngine(validatorMap);
         }
+
+        // Set any custom WSS4J Validator instances that are configured
+        Map<QName, Object> validatorMap = CastUtils.cast(
+            (Map<?, ?>)properties.get(VALIDATOR_MAP));
+        if (validatorMap == null) {
+            validatorMap = CastUtils.cast((Map<?, ?>)properties.get(ConfigurationConstants.VALIDATOR_MAP));
+        }
+        if (validatorMap != null) {
+            for (Map.Entry<QName, Object> entry : validatorMap.entrySet()) {
+                Object val = entry.getValue();
+                if (val instanceof Class<?>) {
+                    config.setValidator(entry.getKey(), (Class<?>)val);
+                } else if (val instanceof Validator) {
+                    config.setValidator(entry.getKey(), (Validator)val);
+                }
+            }
+        }
+
+        secEngineOverride = new WSSecurityEngine();
+        secEngineOverride.setWssConfig(config);
     }
 
+    /**
+     * Setting this value to true means that WSS4J does not compare the "actions" that were processed against
+     * the list of actions that were configured. It also means that CXF/WSS4J does not throw an error if no actions
+     * were specified. Setting this to true could be a potential security risk, as there is then no guarantee that
+     * the message contains the desired security token.
+     */
     public void setIgnoreActions(boolean i) {
         ignoreActions = i;
     }
+
     private SOAPMessage getSOAPMessage(SoapMessage msg) {
         SAAJInInterceptor.INSTANCE.handleMessage(msg);
         return msg.getContent(SOAPMessage.class);
@@ -230,7 +260,6 @@ public class WSS4JInInterceptor extends AbstractWSS4JInterceptor {
 
             computeAction(msg, reqData);
             String action = getAction(msg, version);
-
             List<Integer> actions = WSSecurityUtil.decodeAction(action);
 
             String actor = (String)getOption(ConfigurationConstants.ACTOR);
@@ -578,7 +607,7 @@ public class WSS4JInInterceptor extends AbstractWSS4JInterceptor {
         if (action == null) {
             action = (String)msg.get(ConfigurationConstants.ACTION);
         }
-        if (action == null) {
+        if (action == null && !ignoreActions) {
             LOG.warning("No security action was defined!");
             throw new SoapFault("No security action was defined!", version.getReceiver());
         }
@@ -648,42 +677,17 @@ public class WSS4JInInterceptor extends AbstractWSS4JInterceptor {
         }
 
         if (!utWithCallbacks) {
-            Map<QName, Object> profiles = new HashMap<>(1);
-            Validator validator = new NoOpValidator();
-            profiles.put(WSConstants.USERNAME_TOKEN, validator);
-            return createSecurityEngine(profiles);
+            WSSConfig config = WSSConfig.getNewInstance();
+            config.setValidator(WSConstants.USERNAME_TOKEN, new NoOpValidator());
+            WSSecurityEngine ret = new WSSecurityEngine();
+            ret.setWssConfig(config);
+            return ret;
         }
 
         return null;
     }
 
     /**
-     * @return      a freshly minted WSSecurityEngine instance, using the
-     *              (non-null) processor map, to be used to initialize the
-     *              WSSecurityEngine instance.
-     */
-    protected static WSSecurityEngine createSecurityEngine(final Map<QName, Object> map) {
-        assert map != null;
-        final WSSConfig config = WSSConfig.getNewInstance();
-        for (Map.Entry<QName, Object> entry : map.entrySet()) {
-            final QName key = entry.getKey();
-            Object val = entry.getValue();
-            if (val instanceof Class<?>) {
-                config.setProcessor(key, (Class<?>)val);
-            } else if (val instanceof Processor) {
-                config.setProcessor(key, (Processor)val);
-            } else if (val instanceof Validator) {
-                config.setValidator(key, (Validator)val);
-            } else if (val == null) {
-                config.setProcessor(key, (Class<?>)null);
-            }
-        }
-        final WSSecurityEngine ret = new WSSecurityEngine();
-        ret.setWssConfig(config);
-        return ret;
-    }
-
-    /**
      * Get a ReplayCache instance. It first checks to see whether caching has been explicitly
      * enabled or disabled via the booleanKey argument. If it has been set to false then no
      * replay caching is done (for this booleanKey). If it has not been specified, then caching
diff --git a/systests/kerberos/src/test/java/org/apache/cxf/systest/kerberos/common/KerberosClientPasswordCallback.java b/systests/kerberos/src/test/java/org/apache/cxf/systest/kerberos/common/KerberosClientPasswordCallback.java
index a4a9c84..1626676 100644
--- a/systests/kerberos/src/test/java/org/apache/cxf/systest/kerberos/common/KerberosClientPasswordCallback.java
+++ b/systests/kerberos/src/test/java/org/apache/cxf/systest/kerberos/common/KerberosClientPasswordCallback.java
@@ -27,6 +27,12 @@ import javax.security.auth.callback.NameCallback;
 import javax.security.auth.callback.PasswordCallback;
 import javax.security.auth.callback.UnsupportedCallbackException;
 
+import org.apache.cxf.helpers.DOMUtils;
+import org.apache.wss4j.common.ext.WSPasswordCallback;
+import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.dom.engine.WSSConfig;
+import org.apache.wss4j.dom.message.token.KerberosSecurity;
+
 /**
  * A CallbackHandler implementation for the kerberos client.
  */
@@ -40,6 +46,25 @@ public class KerberosClientPasswordCallback implements CallbackHandler {
             } else if (callbacks[i] instanceof PasswordCallback) {
                 PasswordCallback passwordCallback = (PasswordCallback)callbacks[i];
                 passwordCallback.setPassword("alice".toCharArray());
+            } else if (callbacks[i] instanceof WSPasswordCallback) {
+                WSPasswordCallback wsPasswordCallback = (WSPasswordCallback)callbacks[i];
+                // Get a custom (Kerberos) token directly using the WSS4J APIs
+                if (wsPasswordCallback.getUsage() == WSPasswordCallback.CUSTOM_TOKEN) {
+                    KerberosSecurity kerberosSecurity = new KerberosSecurity(DOMUtils.getEmptyDocument());
+
+                    try {
+                        kerberosSecurity.retrieveServiceTicket("alice", this, "bob@service.ws.apache.org",
+                                                  false, false, null);
+                        kerberosSecurity.addWSUNamespace();
+                        WSSConfig wssConfig = WSSConfig.getNewInstance();
+                        kerberosSecurity.setID(wssConfig.getIdAllocator().createSecureId("BST-", kerberosSecurity));
+
+                        wsPasswordCallback.setCustomToken(kerberosSecurity.getElement());
+                    } catch (WSSecurityException e) {
+                        // TODO Auto-generated catch block
+                        e.printStackTrace();
+                    }
+                }
             }
         }
     }
diff --git a/systests/kerberos/src/test/java/org/apache/cxf/systest/kerberos/wssec/kerberos/KerberosTokenTest.java b/systests/kerberos/src/test/java/org/apache/cxf/systest/kerberos/wssec/kerberos/KerberosTokenTest.java
index 1cf1e62..ad02cf4 100644
--- a/systests/kerberos/src/test/java/org/apache/cxf/systest/kerberos/wssec/kerberos/KerberosTokenTest.java
+++ b/systests/kerberos/src/test/java/org/apache/cxf/systest/kerberos/wssec/kerberos/KerberosTokenTest.java
@@ -434,4 +434,26 @@ public class KerberosTokenTest extends AbstractBusClientServerTestBase {
         bus.shutdown(true);
     }
 
+    @org.junit.Test
+    public void testKerberosViaCustomTokenAction() throws Exception {
+        SpringBusFactory bf = new SpringBusFactory();
+        URL busFile = KerberosTokenTest.class.getResource("client.xml");
+
+        Bus bus = bf.createBus(busFile.toString());
+        BusFactory.setDefaultBus(bus);
+        BusFactory.setThreadDefaultBus(bus);
+
+        URL wsdl = KerberosTokenTest.class.getResource("DoubleItKerberos.wsdl");
+        Service service = Service.create(wsdl, SERVICE_QNAME);
+        QName portQName = new QName(NAMESPACE, "DoubleItKerberosTransportActionPort");
+        DoubleItPortType kerberosPort =
+                service.getPort(portQName, DoubleItPortType.class);
+
+        TestUtil.updateAddressPort(kerberosPort, PORT2);
+
+        Assert.assertEquals(50, kerberosPort.doubleIt(25));
+
+        ((java.io.Closeable)kerberosPort).close();
+        bus.shutdown(true);
+    }
 }
diff --git a/systests/kerberos/src/test/resources/org/apache/cxf/systest/kerberos/wssec/kerberos/DoubleItKerberos.wsdl b/systests/kerberos/src/test/resources/org/apache/cxf/systest/kerberos/wssec/kerberos/DoubleItKerberos.wsdl
index 711c753..f7c1f6b 100644
--- a/systests/kerberos/src/test/resources/org/apache/cxf/systest/kerberos/wssec/kerberos/DoubleItKerberos.wsdl
+++ b/systests/kerberos/src/test/resources/org/apache/cxf/systest/kerberos/wssec/kerberos/DoubleItKerberos.wsdl
@@ -284,6 +284,21 @@
             </wsdl:output>
         </wsdl:operation>
     </wsdl:binding>
+    <wsdl:binding name="DoubleItNoSecurityBinding" type="tns:DoubleItPortType">
+        <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
+        <wsdl:operation name="DoubleIt">
+            <soap:operation soapAction=""/>
+            <wsdl:input>
+                <soap:body use="literal"/>
+            </wsdl:input>
+            <wsdl:output>
+                <soap:body use="literal"/>
+            </wsdl:output>
+            <wsdl:fault name="DoubleItFault">
+                <soap:body use="literal" name="DoubleItFault"/>
+            </wsdl:fault>
+        </wsdl:operation>
+    </wsdl:binding>
     <wsdl:service name="DoubleItService">
         <wsdl:port name="DoubleItKerberosTransportPort" binding="tns:DoubleItKerberosTransportBinding">
             <soap:address location="https://localhost:9009/DoubleItKerberosTransport"/>
@@ -334,6 +349,9 @@
         <wsdl:port name="DoubleItTransportSAML2Port" binding="tns:DoubleItTransportSAML2Binding">
             <soap:address location="https://localhost:8081/doubleit/services/doubleittransportsaml2"/>
         </wsdl:port>
+        <wsdl:port name="DoubleItKerberosTransportActionPort" binding="tns:DoubleItNoSecurityBinding">
+            <soap:address location="https://localhost:9009/DoubleItKerberosTransportAction"/>
+        </wsdl:port>
     </wsdl:service>
     <wsp:Policy wsu:Id="DoubleItKerberosTransportPolicy">
         <wsp:ExactlyOne>
diff --git a/systests/kerberos/src/test/resources/org/apache/cxf/systest/kerberos/wssec/kerberos/client.xml b/systests/kerberos/src/test/resources/org/apache/cxf/systest/kerberos/wssec/kerberos/client.xml
index 649fc85..04d4e69 100644
--- a/systests/kerberos/src/test/resources/org/apache/cxf/systest/kerberos/wssec/kerberos/client.xml
+++ b/systests/kerberos/src/test/resources/org/apache/cxf/systest/kerberos/wssec/kerberos/client.xml
@@ -253,4 +253,17 @@
             </entry>
         </jaxws:properties>
     </jaxws:client>
+    <jaxws:client name="{http://www.example.org/contract/DoubleIt}DoubleItKerberosTransportActionPort" createdFromAPI="true">
+        <jaxws:outInterceptors>
+            <bean class="org.apache.cxf.ws.security.wss4j.WSS4JOutInterceptor">
+                <constructor-arg>
+                    <map>
+                        <entry key="action" value="CustomToken"/>
+                        <entry key="passwordCallbackRef" value-ref="kerberosCallbackHandler"/>
+                    </map>
+                </constructor-arg>
+            </bean>
+        </jaxws:outInterceptors>
+    </jaxws:client>
+    
 </beans>
diff --git a/systests/kerberos/src/test/resources/org/apache/cxf/systest/kerberos/wssec/kerberos/server.xml b/systests/kerberos/src/test/resources/org/apache/cxf/systest/kerberos/wssec/kerberos/server.xml
index 6a634a9..b44473b 100644
--- a/systests/kerberos/src/test/resources/org/apache/cxf/systest/kerberos/wssec/kerberos/server.xml
+++ b/systests/kerberos/src/test/resources/org/apache/cxf/systest/kerberos/wssec/kerberos/server.xml
@@ -17,7 +17,7 @@
  specific language governing permissions and limitations
  under the License.
 -->
-<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:http="http://cxf.apache.org/transports/http/configuration" xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration" xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:interop="http://WSSec/wssec10" xmlns:cxf="http://cxf.apache.org/core" xmlns:p="http://cxf.apache.org/policy" xsi:schemaLocation="         [...]
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:http="http://cxf.apache.org/transports/http/configuration" xmlns:httpj="http://cxf.apache.org/transports/http-jetty/configuration" xmlns:sec="http://cxf.apache.org/configuration/security" xmlns:interop="http://WSSec/wssec10" xmlns:cxf="http://cxf.apache.org/core" xmlns:p="ht [...]
     <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"/>
     <cxf:bus>
         <cxf:features>
@@ -181,6 +181,28 @@
         </jaxws:properties>
     </jaxws:endpoint>
     
+    <bean class="javax.xml.namespace.QName" id="bstQName">
+        <constructor-arg value="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"/>
+        <constructor-arg value="BinarySecurityToken"/>
+    </bean>
+    
+    <util:map id="kerberosValidatorMap">
+        <entry key-ref="bstQName" value-ref="kerberosValidator" />
+    </util:map>
+    
+    <jaxws:endpoint xmlns:s="http://www.example.org/contract/DoubleIt" id="DoubleItKerberosTransportActionPort" address="https://localhost:${testutil.ports.Server.2}/DoubleItKerberosTransportAction" serviceName="s:DoubleItService" endpointName="s:DoubleItKerberosTransportActionPort" implementor="org.apache.cxf.systest.kerberos.common.DoubleItPortTypeImpl" wsdlLocation="org/apache/cxf/systest/kerberos/wssec/kerberos/DoubleItKerberos.wsdl" depends-on="tls-settings">
+        <jaxws:inInterceptors>
+            <bean class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
+                <constructor-arg>
+                    <map>
+                        <entry key="validatorMap" value-ref="kerberosValidatorMap"/>
+                    </map>
+                </constructor-arg>
+                <property name="ignoreActions" value="true"/>
+            </bean>
+        </jaxws:inInterceptors>
+    </jaxws:endpoint>
+    
     <httpj:engine-factory id="STSClientAuthHttpsSettings" bus="cxf">
         <httpj:engine port="${testutil.ports.Server.3}">
             <httpj:tlsServerParameters>