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/05/06 11:59:46 UTC

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

Author: coheigea
Date: Wed May  6 09:59:44 2009
New Revision: 772125

URL: http://svn.apache.org/viewvc?rev=772125&view=rev
Log:
[WSS-183] - Change the UsernameTokenProcessor to validate plaintext passwords
 - Note that Callbacks must still throw an exception for cases other than USERNAME_TOKEN to avoid security holes.

Modified:
    webservices/wss4j/trunk/src/org/apache/ws/security/WSPasswordCallback.java
    webservices/wss4j/trunk/src/org/apache/ws/security/action/UsernameTokenAction.java
    webservices/wss4j/trunk/src/org/apache/ws/security/message/WSSecUsernameToken.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/TestWSSecurityNew5.java

Modified: webservices/wss4j/trunk/src/org/apache/ws/security/WSPasswordCallback.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/WSPasswordCallback.java?rev=772125&r1=772124&r2=772125&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/org/apache/ws/security/WSPasswordCallback.java (original)
+++ webservices/wss4j/trunk/src/org/apache/ws/security/WSPasswordCallback.java Wed May  6 09:59:44 2009
@@ -53,12 +53,11 @@
  * decrypt parts of the SOAP request. Note, the key must match the
  * symmetric encryption/decryption algorithm specified (refer to
  * {@link org.apache.ws.security.handler.WSHandlerConstants#ENC_SYM_ALGO}).</li>
- * <li><code>USERNAME_TOKEN_UNKNOWN</code> - either an not specified 
- * password type or a password type passwordText. In these both cases <b>only</b>
- * the password variable is <b>set</b>. The callback class now may check if
- * the username and password match. If they don't match the callback class must
- * throw an exception. The exception can be a UnsupportedCallbackException or
- * an IOException.</li>
+ * <li><code>USERNAME_TOKEN_UNKNOWN</code> - A not specified password type. 
+ * In this case <b>only</b> the password variable is <b>set</b>. The callback
+ * class now may check if the username and password match. If they don't match
+ * the callback class must throw an exception. The exception can be a 
+ * UnsupportedCallbackException or an IOException.</li>
  * <li><code>SECURITY_CONTEXT_TOKEN</code> - need the key to to be associated 
  * with a <code>wsc:SecurityContextToken</code>.</li>
  * </ul>

Modified: webservices/wss4j/trunk/src/org/apache/ws/security/action/UsernameTokenAction.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/action/UsernameTokenAction.java?rev=772125&r1=772124&r2=772125&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/org/apache/ws/security/action/UsernameTokenAction.java (original)
+++ webservices/wss4j/trunk/src/org/apache/ws/security/action/UsernameTokenAction.java Wed May  6 09:59:44 2009
@@ -28,16 +28,19 @@
 import org.w3c.dom.Document;
 
 public class UsernameTokenAction implements Action {
+    
     public void execute(WSHandler handler, int actionToDo, Document doc, RequestData reqData)
-            throws WSSecurityException {
-        
-        // Always call the callback for the username. We mis-use the configured password callback class and callback methods for this.
-        String providedUsername = reqData.getUsername();
-        WSPasswordCallback callbackData = handler.getPassword(reqData.getUsername(),
-                        actionToDo,
-                        WSHandlerConstants.PW_CALLBACK_CLASS,
-                        WSHandlerConstants.PW_CALLBACK_REF, reqData);
-        providedUsername = callbackData.getIdentifier();
+        throws WSSecurityException {
+
+        WSPasswordCallback callbackData = 
+            handler.getPassword(
+                reqData.getUsername(),
+                actionToDo,
+                WSHandlerConstants.PW_CALLBACK_CLASS,
+                WSHandlerConstants.PW_CALLBACK_REF, 
+                reqData
+            );
+        String providedUsername = callbackData.getIdentifier();
         String password = callbackData.getPassword();
 
         WSSecUsernameToken builder = new WSSecUsernameToken();

Modified: webservices/wss4j/trunk/src/org/apache/ws/security/message/WSSecUsernameToken.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/message/WSSecUsernameToken.java?rev=772125&r1=772124&r2=772125&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/org/apache/ws/security/message/WSSecUsernameToken.java (original)
+++ webservices/wss4j/trunk/src/org/apache/ws/security/message/WSSecUsernameToken.java Wed May  6 09:59:44 2009
@@ -35,7 +35,6 @@
  * 
  * @author Werner Dittmann (werner@apache.org).
  */
-
 public class WSSecUsernameToken extends WSSecBase {
     private static Log log = LogFactory.getLog(WSSecUsernameToken.class.getName());
 
@@ -48,11 +47,6 @@
     private byte[] saltValue;
     private int iteration = UsernameToken.DEFAULT_ITERATION;
 
-    /**
-     * Constructor.
-     */
-    public WSSecUsernameToken() {
-    }
 
     /**
      * Defines how to construct the password element of the
@@ -241,6 +235,6 @@
      * @return the Username Token element
      */
     public Element getUsernameTokenElement() {
-       return this.ut.getElement(); 
+       return ut.getElement(); 
     }
 }

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=772125&r1=772124&r2=772125&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 May  6 09:59:44 2009
@@ -203,12 +203,12 @@
             elementPassword.appendChild(doc.createTextNode(""));
             element.appendChild(elementPassword);
 
-            hashed = false;
             passwordType = pwType;
             if (passwordType.equals(WSConstants.PASSWORD_DIGEST)) {
-                hashed = true;
                 addNonce(doc);
                 addCreated(milliseconds, doc);
+            } else {
+                hashed = false;
             }
         }
     }
@@ -287,7 +287,7 @@
             doc.createElementNS(
                 WSConstants.WSSE11_NS, WSConstants.WSSE11_PREFIX + ":" + WSConstants.SALT_LN
             );
-        WSSecurityUtil.setNamespace(this.element, WSConstants.WSSE11_NS, WSConstants.WSSE11_PREFIX);
+        WSSecurityUtil.setNamespace(element, WSConstants.WSSE11_NS, WSConstants.WSSE11_PREFIX);
         elementSalt.appendChild(doc.createTextNode(Base64.encode(saltValue)));
         element.appendChild(elementSalt);
         return saltValue;
@@ -303,7 +303,7 @@
                 WSConstants.WSSE11_NS, WSConstants.WSSE11_PREFIX + ":" + WSConstants.ITERATION_LN
             );
         WSSecurityUtil.setNamespace(element, WSConstants.WSSE11_NS, WSConstants.WSSE11_PREFIX);
-        this.elementIteration.appendChild(doc.createTextNode(text));
+        elementIteration.appendChild(doc.createTextNode(text));
         element.appendChild(elementIteration);
     }
 
@@ -424,12 +424,13 @@
         rawPassword = pwd;             // enhancement by Alberto coletti
         Text node = getFirstNode(elementPassword);
         try {
-            if (!hashed) {
-                node.setData(pwd);
-                elementPassword.setAttribute("Type", WSConstants.PASSWORD_TEXT);
-            } else {
+            if (hashed) {
                 node.setData(doPasswordDigest(getNonce(), getCreated(), pwd));
-                elementPassword.setAttribute("Type", WSConstants.PASSWORD_DIGEST);
+            } else {
+                node.setData(pwd);
+            }
+            if (passwordType != null) {
+                elementPassword.setAttribute("Type", passwordType);
             }
         } catch (Exception e) {
             if (DO_DEBUG) {
@@ -491,7 +492,7 @@
      */
     private Text getFirstNode(Element e) {
         Node node = e.getFirstChild();
-        return ((node != null) && node instanceof Text) ? (Text) node : null;
+        return (node instanceof Text) ? (Text) node : null;
     }
 
     /**
@@ -527,7 +528,7 @@
      * @return a XML string representation
      */
     public String toString() {
-        return DOM2Writer.nodeToString((Node) this.element);
+        return DOM2Writer.nodeToString((Node)element);
     }
 
     /**

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=772125&r1=772124&r2=772125&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 May  6 09:59:44 2009
@@ -53,7 +53,7 @@
         }
         handleCustomPasswordTypes = wsc.getHandleCustomPasswordTypes();
         
-        Principal lastPrincipalFound = handleUsernameToken((Element) elem, cb);
+        Principal lastPrincipalFound = handleUsernameToken(elem, cb);
         returnResults.add(
             0, 
             new WSSecurityEngineResult(WSConstants.UT, lastPrincipalFound, null, null, null)
@@ -62,17 +62,16 @@
     }
 
     /**
-     * Check the UsernameToken element. Depending on the password type
-     * contained in the element the processing differs. If the password type
-     * is digested, then retrieve a password from the callback handler and
-     * authenticate the UsernameToken here.
+     * Check the UsernameToken element. If the password type is plaintext or digested, 
+     * then retrieve a password from the callback handler and authenticate the UsernameToken
+     * here.
      * <p/>
-     * If the password is in plaintext or any other yet unknown password type
-     * then delegate the password validation to the callback class. Note that for unknown
-     * password types an exception is thrown if WSSConfig.getHandleCustomPasswordTypes()
-     * is set to false (as it is by default). The security engine hands over all necessary
-     * data to the callback class via the WSPasswordCallback object. The usage parameter of
-     * WSPasswordCallback is set to <code>USERNAME_TOKEN_UNKNOWN</code>.
+     * If the password is any other yet unknown password type then delegate the password
+     * validation to the callback class. Note that for unknown password types an exception
+     * is thrown if WSSConfig.getHandleCustomPasswordTypes() is set to false (as it is 
+     * by default). The security engine hands over all necessary data to the callback class
+     * via the WSPasswordCallback object. The usage parameter of WSPasswordCallback is set to
+     * <code>USERNAME_TOKEN_UNKNOWN</code>.
      *
      * @param token the DOM element that contains the UsernameToken
      * @param cb    the reference to the callback object
@@ -98,21 +97,17 @@
             log.debug("UsernameToken user " + user);
             log.debug("UsernameToken password " + password);
         }
-
-        Callback[] callbacks = new Callback[1];
-        String origPassword = null;
-        
         //
-        // If the UsernameToken is hashed, then retrieve the password from the callback handler 
-        // and compare directly. If the UsernameToken is in plaintext or of some unknown type,
+        // If the UsernameToken is hashed or plaintext, then retrieve the password from the
+        // callback handler and compare directly. If the UsernameToken is of some unknown type,
         // then delegate authentication to the callback handler
         //
-        if (ut.isHashed()) {
+        if (ut.isHashed() || WSConstants.PASSWORD_TEXT.equals(pwType) 
+            || (password != null && pwType == null)) {
             WSPasswordCallback pwCb = 
-                new WSPasswordCallback(user, WSPasswordCallback.USERNAME_TOKEN);
-            callbacks[0] = pwCb;
+                new WSPasswordCallback(user, null, pwType, WSPasswordCallback.USERNAME_TOKEN);
             try {
-                cb.handle(callbacks);
+                cb.handle(new Callback[]{pwCb});
             } catch (IOException e) {
                 if (log.isDebugEnabled()) {
                     log.debug(e);
@@ -128,7 +123,7 @@
                     WSSecurityException.FAILED_AUTHENTICATION, null, null, e
                 );
             }
-            origPassword = pwCb.getPassword();
+            String origPassword = pwCb.getPassword();
             if (log.isDebugEnabled()) {
                 log.debug("UsernameToken callback password " + origPassword);
             }
@@ -138,16 +133,20 @@
                 }
                 throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
             }
-            String passDigest = UsernameToken.doPasswordDigest(nonce, createdTime, origPassword);
-            if (!passDigest.equals(password)) {
-                throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
+            if (ut.isHashed()) {
+                String passDigest = 
+                    UsernameToken.doPasswordDigest(nonce, createdTime, origPassword);
+                if (!passDigest.equals(password)) {
+                    throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
+                }
+            } else {
+                if (!origPassword.equals(password)) {
+                    throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
+                }
             }
             ut.setRawPassword(origPassword);
         } else {
-            if (!WSConstants.PASSWORD_TEXT.equals(pwType) 
-                && pwType != null
-                && !handleCustomPasswordTypes
-            ) {
+            if (pwType != null && !handleCustomPasswordTypes) {
                 if (log.isDebugEnabled()) {
                     log.debug("Authentication failed as handleCustomUsernameTokenTypes is false");
                 }
@@ -155,9 +154,8 @@
             }
             WSPasswordCallback pwCb = new WSPasswordCallback(user, password,
                     pwType, WSPasswordCallback.USERNAME_TOKEN_UNKNOWN);
-            callbacks[0] = pwCb;
             try {
-                cb.handle(callbacks);
+                cb.handle(new Callback[]{pwCb});
             } catch (IOException e) {
                 if (log.isDebugEnabled()) {
                     log.debug(e);
@@ -173,7 +171,7 @@
                     WSSecurityException.FAILED_AUTHENTICATION, null, null, e
                 );
             }
-            origPassword = pwCb.getPassword();
+            String origPassword = pwCb.getPassword();
             ut.setRawPassword(origPassword);
         }
         WSUsernameTokenPrincipal principal = new WSUsernameTokenPrincipal(user, ut.isHashed());

Modified: webservices/wss4j/trunk/test/wssec/TestWSSecurityNew5.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/test/wssec/TestWSSecurityNew5.java?rev=772125&r1=772124&r2=772125&view=diff
==============================================================================
--- webservices/wss4j/trunk/test/wssec/TestWSSecurityNew5.java (original)
+++ webservices/wss4j/trunk/test/wssec/TestWSSecurityNew5.java Wed May  6 09:59:44 2009
@@ -366,13 +366,42 @@
     }
     
     /**
-     * Test with a null password type. This will pass as the WSSConfig is configured to 
+     * Test with a non-standard token type. This will fail as the default is to reject custom
+     * token types.
+     */
+    public void testUsernameTokenCustomFail2() throws Exception {
+        WSSecUsernameToken builder = new WSSecUsernameToken();
+        builder.setPasswordType("RandomType");
+        builder.setUserInfo("customUser", "randomPass");
+        
+        Document doc = unsignedEnvelope.getAsDocument();
+        WSSecHeader secHeader = new WSSecHeader();
+        secHeader.insertSecurityHeader(doc);
+        Document signedDoc = builder.build(doc, secHeader);
+        
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Message with UserNameToken PW Text:");
+            String outputString = 
+                org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
+            LOG.debug(outputString);
+        }
+        try {
+            verify(signedDoc);
+            throw new Exception("Custom token types are not permitted");
+        } catch (WSSecurityException ex) {
+            assertTrue(ex.getErrorCode() == WSSecurityException.FAILED_AUTHENTICATION);
+            // expected
+        }
+    }
+    
+    /**
+     * Test with a non-standard password type. This will pass as the WSSConfig is configured to 
      * handle custom token types.
      */
     public void testUsernameTokenCustomPass() throws Exception {
         WSSecUsernameToken builder = new WSSecUsernameToken();
-        builder.setPasswordType(null);
-        builder.setUserInfo("customUser", null);
+        builder.setPasswordType("RandomType");
+        builder.setUserInfo("customUser", "randomPass");
         
         Document doc = unsignedEnvelope.getAsDocument();
         WSSecHeader secHeader = new WSSecHeader();
@@ -380,7 +409,7 @@
         Document signedDoc = builder.build(doc, secHeader);
         
         if (LOG.isDebugEnabled()) {
-            LOG.debug("Message with UserNameToken PW Text:");
+            LOG.debug("Message with UserNameToken PW custom type:");
             String outputString = 
                 org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
             LOG.debug(outputString);
@@ -525,10 +554,7 @@
                 } else if (
                     pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN_UNKNOWN
                 ) {
-                    if ("wernerd".equals(pc.getIdentifier())
-                        && "verySecret".equals(pc.getPassword())) {
-                        return;
-                    } else if ("customUser".equals(pc.getIdentifier())) {
+                    if ("customUser".equals(pc.getIdentifier())) {
                         return;
                     } else {
                         throw new IOException("Authentication failed");



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