You are viewing a plain text version of this content. The canonical link for it is here.
Posted to wss4j-dev@ws.apache.org by co...@apache.org on 2009/06/24 13:11:32 UTC

svn commit: r787976 - in /webservices/wss4j/trunk: src/org/apache/ws/security/ src/org/apache/ws/security/handler/ src/org/apache/ws/security/message/token/ src/org/apache/ws/security/processor/ test/wssec/

Author: coheigea
Date: Wed Jun 24 11:11:31 2009
New Revision: 787976

URL: http://svn.apache.org/viewvc?rev=787976&view=rev
Log:
[WSS-199] - Add support for WCF non-standard Username Tokens
 - I added a new config variable WSHandlerConstants.ALLOW_NAMESPACE_QUALIFIED_PASSWORD_TYPES
 - The default is false. An exception will be thrown in this case when processing a Username Token with a (Wsse) namespace qualified password type

Added:
    webservices/wss4j/trunk/test/wssec/TestWSSecurityWSS199.java   (with props)
Modified:
    webservices/wss4j/trunk/src/org/apache/ws/security/WSSConfig.java
    webservices/wss4j/trunk/src/org/apache/ws/security/handler/WSHandler.java
    webservices/wss4j/trunk/src/org/apache/ws/security/handler/WSHandlerConstants.java
    webservices/wss4j/trunk/src/org/apache/ws/security/message/token/UsernameToken.java
    webservices/wss4j/trunk/src/org/apache/ws/security/processor/UsernameTokenProcessor.java
    webservices/wss4j/trunk/test/wssec/PackageTests.java

Modified: webservices/wss4j/trunk/src/org/apache/ws/security/WSSConfig.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/WSSConfig.java?rev=787976&r1=787975&r2=787976&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/org/apache/ws/security/WSSConfig.java (original)
+++ webservices/wss4j/trunk/src/org/apache/ws/security/WSSConfig.java Wed Jun 24 11:11:31 2009
@@ -204,6 +204,14 @@
      */
     protected boolean handleCustomPasswordTypes = false;
     
+    /**
+     * This variable controls whether (wsse) namespace qualified password types are
+     * accepted when processing UsernameTokens.
+     * 
+     * By default this is set to false.
+     */
+    protected boolean allowNamespaceQualifiedPasswordTypes = false;
+    
     
     /**
      * The default wsu:Id allocator is a simple "start at 1 and increment up"
@@ -386,7 +394,22 @@
     public boolean getHandleCustomPasswordTypes() {
         return handleCustomPasswordTypes;
     }
-
+    
+    /**
+     * @param allowNamespaceQualifiedTypes
+     * whether (wsse) namespace qualified password types are accepted or not
+     */
+    public void setAllowNamespaceQualifiedPasswordTypes(boolean allowNamespaceQualifiedTypes) {
+        allowNamespaceQualifiedPasswordTypes = allowNamespaceQualifiedTypes;
+    }
+    
+    /**
+     * @return whether (wsse) namespace qualified password types are accepted or not
+     */
+    public boolean getAllowNamespaceQualifiedPasswordTypes() {
+        return allowNamespaceQualifiedPasswordTypes;
+    }
+    
     /**
      * @return Returns if we shall throw an exception on expired request
      *         semantic

Modified: webservices/wss4j/trunk/src/org/apache/ws/security/handler/WSHandler.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/handler/WSHandler.java?rev=787976&r1=787975&r2=787976&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/org/apache/ws/security/handler/WSHandler.java (original)
+++ webservices/wss4j/trunk/src/org/apache/ws/security/handler/WSHandler.java Wed Jun 24 11:11:31 2009
@@ -255,6 +255,9 @@
         wssConfig.setTimeStampStrict(decodeTimestampStrict(reqData));
         wssConfig.setTimeStampTTL(decodeTimeToLive(reqData));
         wssConfig.setHandleCustomPasswordTypes(decodeCustomPasswordTypes(reqData));
+        wssConfig.setAllowNamespaceQualifiedPasswordTypes(
+            decodeNamespaceQualifiedPasswordTypes(reqData)
+        );
         reqData.setWssConfig(wssConfig);
 
         if ((doAction & WSConstants.SIGN) == WSConstants.SIGN) {
@@ -729,6 +732,28 @@
             "WSHandler: illegal handleCustomPasswordTypes parameter"
         );
     }
+    
+    protected boolean decodeNamespaceQualifiedPasswordTypes(RequestData reqData) 
+        throws WSSecurityException {
+        String value = getString(
+            WSHandlerConstants.ALLOW_NAMESPACE_QUALIFIED_PASSWORD_TYPES,
+            reqData.getMsgContext()
+        );
+    
+        if (value == null) {
+            return false;
+        }
+        if ("0".equals(value) || "false".equals(value)) {
+            return false;
+        } 
+        if ("1".equals(value) || "true".equals(value)) {
+            return true;
+        }
+    
+        throw new WSSecurityException(
+            "WSHandler: illegal allowNamespaceQualifiedPasswordTypes parameter"
+        );
+    }
 
     protected boolean decodeTimestampStrict(RequestData reqData) 
         throws WSSecurityException {

Modified: webservices/wss4j/trunk/src/org/apache/ws/security/handler/WSHandlerConstants.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/handler/WSHandlerConstants.java?rev=787976&r1=787975&r2=787976&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/org/apache/ws/security/handler/WSHandlerConstants.java (original)
+++ webservices/wss4j/trunk/src/org/apache/ws/security/handler/WSHandlerConstants.java Wed Jun 24 11:11:31 2009
@@ -497,6 +497,15 @@
      * reject custom token types in the callback handler.
      */
     public static final String HANDLE_CUSTOM_PASSWORD_TYPES = "handleCustomPasswordTypes";
+    
+    /**
+     * This variable controls whether (wsse) namespace qualified password types are
+     * accepted when processing UsernameTokens.
+     * 
+     * By default this is set to false.
+     */
+    public static final String ALLOW_NAMESPACE_QUALIFIED_PASSWORD_TYPES 
+        = "allowNamespaceQualifiedPasswordTypes";
 
     /**
      * Parameter to generate additional elements in <code>UsernameToken</code>.

Modified: webservices/wss4j/trunk/src/org/apache/ws/security/message/token/UsernameToken.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/message/token/UsernameToken.java?rev=787976&r1=787975&r2=787976&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/org/apache/ws/security/message/token/UsernameToken.java (original)
+++ webservices/wss4j/trunk/src/org/apache/ws/security/message/token/UsernameToken.java Wed Jun 24 11:11:31 2009
@@ -75,7 +75,7 @@
     protected String passwordType = null;
     protected boolean hashed = true;
     private String rawPassword;        // enhancement by Alberto Coletti
-
+    
     static {
         try {
             random = WSSecurityUtil.resolveSecureRandom();
@@ -85,7 +85,7 @@
             }
         }
     }
-
+    
     /**
      * Constructs a <code>UsernameToken</code> object and parses the
      * <code>wsse:UsernameToken</code> element to initialize it.
@@ -95,6 +95,23 @@
      * @throws WSSecurityException
      */
     public UsernameToken(Element elem) throws WSSecurityException {
+        this (elem, false);
+    }
+
+    /**
+     * Constructs a <code>UsernameToken</code> object and parses the
+     * <code>wsse:UsernameToken</code> element to initialize it.
+     * 
+     * @param elem the <code>wsse:UsernameToken</code> element that contains
+     *             the UsernameToken data
+     * @param allowNamespaceQualifiedPasswordTypes whether to allow (wsse)
+     *        namespace qualified password types or not (for interop with WCF)
+     * @throws WSSecurityException
+     */
+    public UsernameToken(
+        Element elem, 
+        boolean allowNamespaceQualifiedPasswordTypes
+    ) throws WSSecurityException {
         element = elem;
         QName el = new QName(element.getNamespaceURI(), element.getLocalName());
         if (!el.equals(TOKEN)) {
@@ -151,9 +168,26 @@
             }
             return;
         }
-        if (elementPassword != null 
-            && elementPassword.hasAttribute(WSConstants.PASSWORD_TYPE_ATTR)) {
-            passwordType = elementPassword.getAttribute(WSConstants.PASSWORD_TYPE_ATTR);
+        if (elementPassword != null) {
+            if (elementPassword.hasAttribute(WSConstants.PASSWORD_TYPE_ATTR)) {
+                passwordType = elementPassword.getAttribute(WSConstants.PASSWORD_TYPE_ATTR);
+            } else if (elementPassword.hasAttributeNS(
+                WSConstants.WSSE_NS, WSConstants.PASSWORD_TYPE_ATTR)
+            ) {
+                if (allowNamespaceQualifiedPasswordTypes) {
+                    passwordType = 
+                        elementPassword.getAttributeNS(
+                            WSConstants.WSSE_NS, WSConstants.PASSWORD_TYPE_ATTR
+                        );
+                } else {
+                    throw new WSSecurityException(
+                        WSSecurityException.INVALID_SECURITY_TOKEN,
+                        "badTokenType01", 
+                        new Object[] {el}
+                    );
+                }
+            }
+            
         }
         if (WSConstants.PASSWORD_DIGEST.equals(passwordType)) {
             hashed = true;

Modified: webservices/wss4j/trunk/src/org/apache/ws/security/processor/UsernameTokenProcessor.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/processor/UsernameTokenProcessor.java?rev=787976&r1=787975&r2=787976&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/org/apache/ws/security/processor/UsernameTokenProcessor.java (original)
+++ webservices/wss4j/trunk/src/org/apache/ws/security/processor/UsernameTokenProcessor.java Wed Jun 24 11:11:31 2009
@@ -45,6 +45,7 @@
     private String utId;
     private UsernameToken ut;
     private boolean handleCustomPasswordTypes;
+    private boolean allowNamespaceQualifiedPasswordTypes;
     
     public void handleToken(Element elem, Crypto crypto, Crypto decCrypto, CallbackHandler cb, 
         WSDocInfo wsDocInfo, List returnResults, WSSConfig wsc) throws WSSecurityException {
@@ -52,6 +53,7 @@
             log.debug("Found UsernameToken list element");
         }
         handleCustomPasswordTypes = wsc.getHandleCustomPasswordTypes();
+        allowNamespaceQualifiedPasswordTypes = wsc.getAllowNamespaceQualifiedPasswordTypes();
         
         Principal lastPrincipalFound = handleUsernameToken(elem, cb);
         returnResults.add(
@@ -87,7 +89,7 @@
         //
         // Parse the UsernameToken element
         //
-        ut = new UsernameToken(token);
+        ut = new UsernameToken(token, allowNamespaceQualifiedPasswordTypes);
         String user = ut.getName();
         String password = ut.getPassword();
         String nonce = ut.getNonce();

Modified: webservices/wss4j/trunk/test/wssec/PackageTests.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/test/wssec/PackageTests.java?rev=787976&r1=787975&r2=787976&view=diff
==============================================================================
--- webservices/wss4j/trunk/test/wssec/PackageTests.java (original)
+++ webservices/wss4j/trunk/test/wssec/PackageTests.java Wed Jun 24 11:11:31 2009
@@ -76,6 +76,7 @@
         suite.addTestSuite(SignatureConfirmationTest.class);
         suite.addTestSuite(TestWSSecurityWSS194.class);
         suite.addTestSuite(TestModifiedRequest.class);
+        suite.addTestSuite(TestWSSecurityWSS199.class);
         
         return suite;
     }

Added: webservices/wss4j/trunk/test/wssec/TestWSSecurityWSS199.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/test/wssec/TestWSSecurityWSS199.java?rev=787976&view=auto
==============================================================================
--- webservices/wss4j/trunk/test/wssec/TestWSSecurityWSS199.java (added)
+++ webservices/wss4j/trunk/test/wssec/TestWSSecurityWSS199.java Wed Jun 24 11:11:31 2009
@@ -0,0 +1,164 @@
+/**
+ * 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 wssec;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ws.security.WSSecurityException;
+import org.apache.ws.security.WSPasswordCallback;
+import org.apache.ws.security.WSSecurityEngine;
+import org.apache.ws.security.WSConstants;
+import org.apache.ws.security.WSSConfig;
+import org.apache.ws.security.message.WSSecUsernameToken;
+import org.apache.ws.security.message.WSSecHeader;
+import org.apache.ws.security.util.Base64;
+import org.w3c.dom.Document;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+import java.io.IOException;
+import java.security.MessageDigest;
+
+
+/**
+ * A test-case for WSS-199 - "Add support for WCF non-standard Username Tokens"
+ * (see also WSS-148 - "WCF interop issue: Namespace not honored incase of attributes.").
+ * The issue is that WCF generated Username Tokens where the password type is namespace
+ * qualified (incorrectly). WSS-199 added the ability to process these Username Tokens.
+ */
+public class TestWSSecurityWSS199 extends TestCase implements CallbackHandler {
+    private static final Log LOG = LogFactory.getLog(TestWSSecurityWSS199.class);
+    private static final String SOAPUTMSG = 
+        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" 
+        + "<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" "
+        + "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" "
+        + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
+        + "<SOAP-ENV:Header>"
+        + "<wsse:Security SOAP-ENV:mustUnderstand=\"1\" "
+        + "xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd\">"
+        + "<wsse:UsernameToken wsu:Id=\"UsernameToken-29477163\" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd\">"
+        + "<wsse:Username>wernerd</wsse:Username>"
+        + "<wsse:Password " 
+        + "wsse:Type=\"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText\">verySecret</wsse:Password>"
+        + "</wsse:UsernameToken></wsse:Security></SOAP-ENV:Header>"
+        + "<SOAP-ENV:Body>" 
+        + "<add xmlns=\"http://ws.apache.org/counter/counter_port_type\">" 
+        + "<value xmlns=\"\">15</value>" + "</add>" 
+        + "</SOAP-ENV:Body>\r\n       \r\n" + "</SOAP-ENV:Envelope>";
+    
+    private WSSecurityEngine secEngine = new WSSecurityEngine();
+
+    /**
+     * TestWSSecurity constructor
+     * 
+     * @param name name of the test
+     */
+    public TestWSSecurityWSS199(String name) {
+        super(name);
+    }
+
+    /**
+     * JUnit suite
+     * 
+     * @return a junit test suite
+     */
+    public static Test suite() {
+        return new TestSuite(TestWSSecurityWSS199.class);
+    }
+
+
+    /**
+     * Test that adds a UserNameToken with a namespace qualified type. This should fail
+     * as WSS4J rejects these tokens by default.
+     */
+    public void testNamespaceQualifiedTypeRejected() throws Exception {
+        Document doc = SOAPUtil.toSOAPPart(SOAPUTMSG);
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Message with UserNameToken PW Digest:");
+            String outputString = 
+                org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
+            LOG.debug(outputString);
+        }
+        try {
+            verify(doc);
+            fail("Failure expected on a bad password type");
+        } catch (WSSecurityException ex) {
+            // expected
+        }
+    }
+    
+    
+    /**
+     * Test that adds a UserNameToken with a namespace qualified type. This should pass
+     * as WSS4J has been configured to accept these tokens.
+     */
+    public void testNamespaceQualifiedTypeAccepted() throws Exception {
+        Document doc = SOAPUtil.toSOAPPart(SOAPUTMSG);
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Message with UserNameToken PW Digest:");
+            String outputString = 
+                org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
+            LOG.debug(outputString);
+        }
+        WSSConfig wssConfig = secEngine.getWssConfig();
+        wssConfig.setAllowNamespaceQualifiedPasswordTypes(true);
+        secEngine.setWssConfig(wssConfig);
+        verify(doc);
+    }
+    
+    
+    /**
+     * Verifies the soap envelope
+     * 
+     * @param env soap envelope
+     * @throws java.lang.Exception Thrown when there is a problem in verification
+     */
+    private void verify(Document doc) throws Exception {
+        LOG.info("Before verifying UsernameToken....");
+        secEngine.processSecurityHeader(doc, null, this, null);
+        LOG.info("After verifying UsernameToken....");
+    }
+
+    public void handle(Callback[] callbacks)
+        throws IOException, UnsupportedCallbackException {
+        for (int i = 0; i < callbacks.length; i++) {
+            if (callbacks[i] instanceof WSPasswordCallback) {
+                WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
+                assertEquals(pc.getPasswordType(), WSConstants.PASSWORD_TEXT);
+                if (pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN
+                    && "wernerd".equals(pc.getIdentifier())) {
+                    pc.setPassword("verySecret");
+                } else if (
+                    pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN_UNKNOWN
+                ) {
+                    throw new IOException("Authentication failed");
+                }
+            } else {
+                throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
+            }
+        }
+    }
+}

Propchange: webservices/wss4j/trunk/test/wssec/TestWSSecurityWSS199.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: webservices/wss4j/trunk/test/wssec/TestWSSecurityWSS199.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date



---------------------------------------------------------------------
To unsubscribe, e-mail: wss4j-dev-unsubscribe@ws.apache.org
For additional commands, e-mail: wss4j-dev-help@ws.apache.org