Author: coheigea
Date: Tue Nov  9 12:52:16 2010
New Revision: 1032974

URL: http://svn.apache.org/viewvc?rev=1032974&view=rev
Log:
[WSS-239] - Forward merged to trunk.

Modified:
    webservices/wss4j/trunk/   (props changed)
    webservices/wss4j/trunk/src/org/apache/ws/security/WSDocInfo.java   (props 
changed)
    webservices/wss4j/trunk/src/org/apache/ws/security/WSSConfig.java
    
webservices/wss4j/trunk/src/org/apache/ws/security/action/UsernameTokenAction.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/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
    webservices/wss4j/trunk/test/wssec/TestWSSecurityUTDK.java

Propchange: webservices/wss4j/trunk/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Nov  9 12:52:16 2010
@@ -1 +1 @@
-/webservices/wss4j/branches/1_5_x-fixes:996180,996298,996339,997529,997535,1001926,1002116,1002347
+/webservices/wss4j/branches/1_5_x-fixes:996180,996298,996339,997529,997535,1001926,1002116,1002347,1032939

Propchange: webservices/wss4j/trunk/src/org/apache/ws/security/WSDocInfo.java
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Nov  9 12:52:16 2010
@@ -1 +1 @@
-/webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/WSDocInfo.java:947604,996180,996298,996339,997529,997535,1001926,1002116,1002347
+/webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/WSDocInfo.java:947604,996180,996298,996339,997529,997535,1001926,1002116,1002347,1032939

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=1032974&r1=1032973&r2=1032974&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/org/apache/ws/security/WSSConfig.java (original)
+++ webservices/wss4j/trunk/src/org/apache/ws/security/WSSConfig.java Tue Nov  
9 12:52:16 2010
@@ -218,6 +218,19 @@ public class WSSConfig {
      * The secret key length to be used for UT_SIGN.
      */
     protected int secretKeyLength = WSConstants.WSE_DERIVED_KEY_LEN;
+
+    /**
+     * Whether the password should be treated as a binary value.  This
+     * is needed to properly handle password equivalence for UsernameToken
+     * passwords.  Binary passwords are Base64 encoded so they can be
+     * treated as strings in most places, but when the password digest
+     * is calculated or a key is derived from the password, the password
+     * will be Base64 decoded before being used. This is most useful for
+     * hashed passwords as password equivalents.
+     *
+     * See https://issues.apache.org/jira/browse/WSS-239
+     */
+    protected boolean passwordsAreEncoded = false;
     
     /**
      * The default wsu:Id allocator is a simple "start at 1 and increment up"
@@ -455,6 +468,21 @@ public class WSSConfig {
     }
     
     /**
+     * @param passwordsAreEncoded
+     * whether passwords are encoded
+     */
+    public void setPasswordsAreEncoded(boolean passwordsAreEncoded) {
+        this.passwordsAreEncoded = passwordsAreEncoded;
+    }
+    
+    /**
+     * @return whether passwords are encoded
+     */
+    public boolean getPasswordsAreEncoded() {
+        return passwordsAreEncoded;
+    }
+    
+    /**
      * @return Returns the WsuIdAllocator used to generate wsu:Id attributes
      */
     public WsuIdAllocator getIdAllocator() {

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=1032974&r1=1032973&r2=1032974&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
 Tue Nov  9 12:52:16 2010
@@ -46,6 +46,7 @@ public class UsernameTokenAction impleme
         WSSecUsernameToken builder = new WSSecUsernameToken();
         builder.setWsConfig(reqData.getWssConfig());
         builder.setPasswordType(reqData.getPwType());
+        
builder.setPasswordsAreEncoded(reqData.getWssConfig().getPasswordsAreEncoded());
         builder.setUserInfo(providedUsername, password);
 
         if (reqData.getUtElements() != null && reqData.getUtElements().length 
> 0) {

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=1032974&r1=1032973&r2=1032974&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 
Tue Nov  9 12:52:16 2010
@@ -97,6 +97,7 @@ public abstract class WSHandler {
         wssConfig.setEnableSignatureConfirmation(
             enableSigConf || ((doAction & WSConstants.SC) != 0)
         );
+        wssConfig.setPasswordsAreEncoded(decodeUseEncodedPasswords(reqData));
 
         wssConfig.setPrecisionInMilliSeconds(
             decodeTimestampPrecision(reqData)
@@ -257,6 +258,7 @@ public abstract class WSHandler {
         wssConfig.setTimeStampStrict(decodeTimestampStrict(reqData));
         wssConfig.setTimeStampTTL(decodeTimeToLive(reqData));
         
wssConfig.setHandleCustomPasswordTypes(decodeCustomPasswordTypes(reqData));
+        wssConfig.setPasswordsAreEncoded(decodeUseEncodedPasswords(reqData));
         wssConfig.setAllowNamespaceQualifiedPasswordTypes(
             decodeNamespaceQualifiedPasswordTypes(reqData)
         );
@@ -761,6 +763,28 @@ public abstract class WSHandler {
         );
     }
     
+    protected boolean decodeUseEncodedPasswords(RequestData reqData) 
+        throws WSSecurityException {
+        String value = getString(
+            WSHandlerConstants.USE_ENCODED_PASSWORDS,
+            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 useEncodedPasswords parameter"
+        );
+    }
+    
     protected boolean decodeNamespaceQualifiedPasswordTypes(RequestData 
reqData) 
         throws WSSecurityException {
         String value = getString(

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=1032974&r1=1032973&r2=1032974&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
 Tue Nov  9 12:52:16 2010
@@ -801,6 +801,18 @@ public class WSHandlerConstants {
     public static final String TIMESTAMP_STRICT = "timestampStrict";
     
     /**
+     * Set the value of this parameter to true to treat passwords as binary 
values
+     * for Username Tokens.
+     * 
+     * This is needed to properly handle password equivalence for UsernameToken
+     * passwords.  Binary passwords are Base64 encoded so they can be treated 
as 
+     * strings in most places, but when the password digest is calculated or a 
key
+     * is derived from the password, the password will be Base64 decoded 
before 
+     * being used. This is most useful for hashed passwords as password 
equivalents.
+     */
+    public static final String USE_ENCODED_PASSWORDS = "useEncodedPasswords";
+    
+    /**
      * Define the parameter values to set the key identifier types. These are:
      * <ul>
      * <li><code>DirectReference</code> for {...@link 
WSConstants#BST_DIRECT_REFERENCE}

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=1032974&r1=1032973&r2=1032974&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
 Tue Nov  9 12:52:16 2010
@@ -24,6 +24,7 @@ import org.apache.commons.logging.LogFac
 import org.apache.ws.security.WSConstants;
 import org.apache.ws.security.WSSecurityException;
 import org.apache.ws.security.message.token.UsernameToken;
+import org.apache.ws.security.util.Base64;
 import org.apache.ws.security.util.WSSecurityUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
@@ -47,6 +48,7 @@ public class WSSecUsernameToken extends 
     private byte[] saltValue;
     private int iteration = UsernameToken.DEFAULT_ITERATION;
     private int secretKeyLength = WSConstants.WSE_DERIVED_KEY_LEN;
+    private boolean passwordsAreEncoded = false;
 
 
     /**
@@ -124,7 +126,11 @@ public class WSSecUsernameToken extends 
             return null;
         }
         if (useDerivedKey) {
-            return UsernameToken.generateDerivedKey(password, saltValue, 
iteration);
+            if (passwordsAreEncoded) {
+                return 
UsernameToken.generateDerivedKey(Base64.decode(password), saltValue, iteration);
+            } else {
+                return UsernameToken.generateDerivedKey(password, saltValue, 
iteration);
+            }
         }
         return ut.getSecretKey(secretKeyLength);
     }
@@ -143,7 +149,26 @@ public class WSSecUsernameToken extends 
         if (ut == null || !useDerivedKey) {
             return null;
         }
-        return UsernameToken.generateDerivedKey(password, saltValue, 
iteration);
+        if (passwordsAreEncoded) {
+            return UsernameToken.generateDerivedKey(Base64.decode(password), 
saltValue, iteration);
+        } else {
+            return UsernameToken.generateDerivedKey(password, saltValue, 
iteration);
+        }
+    }
+
+    /**
+     * @param passwordsAreEncoded
+     * whether passwords are encoded
+     */
+    public void setPasswordsAreEncoded(boolean passwordsAreEncoded) {
+        this.passwordsAreEncoded = passwordsAreEncoded;
+    }
+
+    /**
+     * @return whether passwords are encoded
+     */
+    public boolean getPasswordsAreEncoded() {
+        return passwordsAreEncoded;
     }
 
     /**
@@ -174,6 +199,7 @@ public class WSSecUsernameToken extends 
      */
     public void prepare(Document doc) {
         ut = new UsernameToken(wssConfig.isPrecisionInMilliSeconds(), doc, 
passwordType);
+        ut.setPasswordsAreEncoded(passwordsAreEncoded);
         ut.setName(user);
         if (useDerivedKey) {
             saltValue = ut.addSalt(doc, saltValue, useMac);

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=1032974&r1=1032973&r2=1032974&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
 Tue Nov  9 12:52:16 2010
@@ -75,6 +75,7 @@ public class UsernameToken {
     protected String passwordType = null;
     protected boolean hashed = true;
     private String rawPassword;        // enhancement by Alberto Coletti
+    private boolean passwordsAreEncoded = false;
     
     static {
         try {
@@ -465,7 +466,11 @@ public class UsernameToken {
         Text node = getFirstNode(elementPassword);
         try {
             if (hashed) {
-                node.setData(doPasswordDigest(getNonce(), getCreated(), pwd));
+                if (passwordsAreEncoded) {
+                    node.setData(doPasswordDigest(getNonce(), getCreated(), 
Base64.decode(pwd)));
+                } else {
+                    node.setData(doPasswordDigest(getNonce(), getCreated(), 
pwd));
+                }
             } else {
                 node.setData(pwd);
             }
@@ -495,12 +500,26 @@ public class UsernameToken {
         return rawPassword;
     }
     
-    public static String doPasswordDigest(String nonce, String created, String 
password) {
+    /**
+     * @param passwordsAreEncoded whether passwords are encoded
+     */
+    public void setPasswordsAreEncoded(boolean passwordsAreEncoded) {
+        this.passwordsAreEncoded = passwordsAreEncoded;
+    }
+    
+    /**
+     * @return whether passwords are encoded
+     */
+    public boolean getPasswordsAreEncoded() {
+        return passwordsAreEncoded;
+    }
+    
+    public static String doPasswordDigest(String nonce, String created, byte[] 
password) {
         String passwdDigest = null;
         try {
             byte[] b1 = nonce != null ? Base64.decode(nonce) : new byte[0];
             byte[] b2 = created != null ? created.getBytes("UTF-8") : new 
byte[0];
-            byte[] b3 = password.getBytes("UTF-8");
+            byte[] b3 = password;
             byte[] b4 = new byte[b1.length + b2.length + b3.length];
             int offset = 0;
             System.arraycopy(b1, 0, b4, offset, b1.length);
@@ -523,6 +542,18 @@ public class UsernameToken {
         return passwdDigest;
     }
 
+    public static String doPasswordDigest(String nonce, String created, String 
password) {
+        String passwdDigest = null;
+        try {
+            passwdDigest = doPasswordDigest(nonce, created, 
password.getBytes("UTF-8"));
+        } catch (Exception e) {
+            if (DO_DEBUG) {
+                LOG.debug(e.getMessage(), e);
+            }
+        }
+        return passwdDigest;
+    }
+
     /**
      * Returns the first text node of an element.
      * 
@@ -627,7 +658,12 @@ public class UsernameToken {
         byte[] key = null;
         try {
             Mac mac = Mac.getInstance("HMACSHA1");
-            byte[] password = rawPassword.getBytes("UTF-8"); // enhancement by 
Alberto Coletti
+            byte[] password;
+            if (passwordsAreEncoded) {
+                password = Base64.decode(rawPassword);
+            } else {
+                password = rawPassword.getBytes("UTF-8"); // enhancement by 
Alberto Coletti
+            }
             byte[] label = labelString.getBytes("UTF-8");
             byte[] nonce = Base64.decode(getNonce());
             byte[] created = getCreated().getBytes("UTF-8");
@@ -661,7 +697,7 @@ public class UsernameToken {
         return key;
     }
     
-  
+    
     /**
      * This static method generates a derived key as defined in WSS Username
      * Token Profile.
@@ -674,26 +710,17 @@ public class UsernameToken {
      * @throws WSSecurityException
      */
     public static byte[] generateDerivedKey(
-        String password, 
+        byte[] password, 
         byte[] salt, 
         int iteration
     ) throws WSSecurityException {
         if (iteration == 0) {
             iteration = DEFAULT_ITERATION;
         }
-        byte[] pwBytes = null;
-        try {
-            pwBytes = password.getBytes("UTF-8");
-        } catch (final java.io.UnsupportedEncodingException e) {
-            if (DO_DEBUG) {
-                LOG.debug(e.getMessage(), e);
-            }
-            throw new WSSecurityException("Unable to convert password to 
UTF-8", e);
-        }
 
-        byte[] pwSalt = new byte[salt.length + pwBytes.length];
-        System.arraycopy(pwBytes, 0, pwSalt, 0, pwBytes.length);
-        System.arraycopy(salt, 0, pwSalt, pwBytes.length, salt.length);
+        byte[] pwSalt = new byte[salt.length + password.length];
+        System.arraycopy(password, 0, pwSalt, 0, password.length);
+        System.arraycopy(salt, 0, pwSalt, password.length, salt.length);
 
         MessageDigest sha = null;
         try {
@@ -721,6 +748,32 @@ public class UsernameToken {
         return K;
     }
     
+    /**
+     * This static method generates a derived key as defined in WSS Username
+     * Token Profile.
+     * 
+     * @param password The password to include in the key generation
+     * @param salt The Salt value
+     * @param iteration The Iteration value. If zero (0) is given the method 
uses the
+     *                  default value
+     * @return Returns the derived key a byte array
+     * @throws WSSecurityException
+     */
+    public static byte[] generateDerivedKey(
+        String password, 
+        byte[] salt, 
+        int iteration
+    ) throws WSSecurityException {
+        try {
+            return generateDerivedKey(password.getBytes("UTF-8"), salt, 
iteration);
+        } catch (final java.io.UnsupportedEncodingException e) {
+            if (DO_DEBUG) {
+                LOG.debug(e.getMessage(), e);
+            }
+            throw new WSSecurityException("Unable to convert password to 
UTF-8", e);
+        }
+    }
+    
     
     /**
      * This method gets a derived key as defined in WSS Username Token Profile.
@@ -731,7 +784,11 @@ public class UsernameToken {
     public byte[] getDerivedKey() throws WSSecurityException {
         int iteration = getIteration();
         byte[] salt = getSalt();
-        return generateDerivedKey(rawPassword, salt, iteration);
+        if (passwordsAreEncoded) {
+            return generateDerivedKey(Base64.decode(rawPassword), salt, 
iteration);
+        } else {
+            return generateDerivedKey(rawPassword, salt, iteration);
+        }
     }
     
     /**

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=1032974&r1=1032973&r2=1032974&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
 Tue Nov  9 12:52:16 2010
@@ -30,6 +30,7 @@ import org.apache.ws.security.WSSecurity
 import org.apache.ws.security.WSUsernameTokenPrincipal;
 import org.apache.ws.security.components.crypto.Crypto;
 import org.apache.ws.security.message.token.UsernameToken;
+import org.apache.ws.security.util.Base64;
 import org.w3c.dom.Element;
 
 import javax.security.auth.callback.Callback;
@@ -46,6 +47,7 @@ public class UsernameTokenProcessor impl
     private UsernameToken ut;
     private boolean handleCustomPasswordTypes;
     private boolean allowNamespaceQualifiedPasswordTypes;
+    private boolean passwordsAreEncoded;
     
     public void handleToken(Element elem, Crypto crypto, Crypto decCrypto, 
CallbackHandler cb, 
         WSDocInfo wsDocInfo, List returnResults, WSSConfig wsc) throws 
WSSecurityException {
@@ -54,6 +56,7 @@ public class UsernameTokenProcessor impl
         }
         handleCustomPasswordTypes = wsc.getHandleCustomPasswordTypes();
         allowNamespaceQualifiedPasswordTypes = 
wsc.getAllowNamespaceQualifiedPasswordTypes();
+        passwordsAreEncoded = wsc.getPasswordsAreEncoded();
         
         Principal lastPrincipalFound = handleUsernameToken(elem, cb);
         returnResults.add(
@@ -90,6 +93,7 @@ public class UsernameTokenProcessor impl
         // Parse the UsernameToken element
         //
         ut = new UsernameToken(token, allowNamespaceQualifiedPasswordTypes);
+        ut.setPasswordsAreEncoded(passwordsAreEncoded);
         String user = ut.getName();
         String password = ut.getPassword();
         String nonce = ut.getNonce();
@@ -136,8 +140,12 @@ public class UsernameTokenProcessor impl
                 throw new 
WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
             }
             if (ut.isHashed()) {
-                String passDigest = 
-                    UsernameToken.doPasswordDigest(nonce, createdTime, 
origPassword);
+                String passDigest;
+                if (passwordsAreEncoded) {
+                    passDigest = UsernameToken.doPasswordDigest(nonce, 
createdTime, Base64.decode(origPassword));
+                } else {
+                    passDigest = UsernameToken.doPasswordDigest(nonce, 
createdTime, origPassword);
+                }
                 if (!passDigest.equals(password)) {
                     throw new 
WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
                 }
@@ -208,6 +216,10 @@ public class UsernameTokenProcessor impl
         }
         byte[] saltValue = ut.getSalt();
         int iteration = ut.getIteration();
-        return UsernameToken.generateDerivedKey(password, saltValue, 
iteration);
+        if (passwordsAreEncoded) {
+            return UsernameToken.generateDerivedKey(Base64.decode(password), 
saltValue, iteration);
+        } else {
+            return UsernameToken.generateDerivedKey(password, saltValue, 
iteration);
+        }
     }
 }

Modified: webservices/wss4j/trunk/test/wssec/TestWSSecurityNew5.java
URL: 
http://svn.apache.org/viewvc/webservices/wss4j/trunk/test/wssec/TestWSSecurityNew5.java?rev=1032974&r1=1032973&r2=1032974&view=diff
==============================================================================
--- webservices/wss4j/trunk/test/wssec/TestWSSecurityNew5.java (original)
+++ webservices/wss4j/trunk/test/wssec/TestWSSecurityNew5.java Tue Nov  9 
12:52:16 2010
@@ -33,6 +33,7 @@ import org.apache.ws.security.handler.Re
 import org.apache.ws.security.handler.WSHandlerConstants;
 import org.apache.ws.security.message.WSSecUsernameToken;
 import org.apache.ws.security.message.WSSecHeader;
+import org.apache.ws.security.message.token.UsernameToken;
 import org.apache.ws.security.util.Base64;
 import org.w3c.dom.Document;
 
@@ -42,7 +43,6 @@ import javax.security.auth.callback.Unsu
 import java.io.IOException;
 import java.security.MessageDigest;
 
-
 /**
  * WS-Security Test Case for UsernameTokens.
  * 
@@ -158,6 +158,51 @@ public class TestWSSecurityNew5 extends 
     }
     
     /**
+     * Test for encoded passwords.
+     */
+    public void testUsernameTokenWithEncodedPasswordBaseline() throws 
Exception {
+        String password = "password";
+        // The SHA-1 of the password is known as a password equivalent in the 
UsernameToken specification.
+        byte[] passwordHash = 
MessageDigest.getInstance("SHA-1").digest(password.getBytes("UTF-8"));
+
+        String nonce = "0x7bXAPZVn40AdCD0Xbt0g==";
+        String created = "2010-06-28T15:16:37Z";
+        String expectedPasswordDigest = "C0rena/6gKpRZ9ATj+e6ss5sAbQ=";
+        String actualPasswordDigest = UsernameToken.doPasswordDigest(nonce, 
created, passwordHash);
+        assertEquals("the password digest is not as expected", 
expectedPasswordDigest, actualPasswordDigest);
+    }
+    
+    /**
+     * Test that adds a UserNameToken with password Digest to a WS-Security 
envelope
+     */
+    public void testUsernameTokenWithEncodedPassword() throws Exception {
+        WSSecUsernameToken builder = new WSSecUsernameToken();
+        builder.setPasswordsAreEncoded(true);
+        builder.setUserInfo("wernerd", 
Base64.encode(MessageDigest.getInstance("SHA-1").digest("verySecret".getBytes("UTF-8"))));
+        LOG.info("Before adding UsernameToken PW Digest....");
+        Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
+        WSSecHeader secHeader = new WSSecHeader();
+        secHeader.insertSecurityHeader(doc);
+        Document signedDoc = builder.build(doc, secHeader);
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Message with UserNameToken PW Digest:");
+            String outputString = 
+                
org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
+            LOG.debug(outputString);
+        }
+        LOG.info("After adding UsernameToken PW Digest....");
+
+        boolean passwordsAreEnabledOrig = 
WSSecurityEngine.getInstance().getWssConfig().getPasswordsAreEncoded();
+        try {
+            
WSSecurityEngine.getInstance().getWssConfig().setPasswordsAreEncoded(true);
+            verify(signedDoc);
+        } finally {
+            
WSSecurityEngine.getInstance().getWssConfig().setPasswordsAreEncoded(passwordsAreEnabledOrig);
+        }
+    }
+    
+    /**
      * Test that a bad username with password digest does not leak whether the 
username
      * is valid or not - see WSS-141.
      */
@@ -659,9 +704,15 @@ public class TestWSSecurityNew5 extends 
         for (int i = 0; i < callbacks.length; i++) {
             if (callbacks[i] instanceof WSPasswordCallback) {
                 WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
+                boolean passwordsAreEncoded = 
WSSecurityEngine.getInstance().getWssConfig().getPasswordsAreEncoded();
                 if (pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN
                     && "wernerd".equals(pc.getIdentifier())) {
-                    pc.setPassword("verySecret");
+                    if (passwordsAreEncoded) {
+                        // "hGqoUreBgahTJblQ3DbJIkE6uNs=" is the Base64 
encoded SHA-1 hash of "verySecret".
+                        pc.setPassword("hGqoUreBgahTJblQ3DbJIkE6uNs=");
+                    } else {
+                        pc.setPassword("verySecret");
+                    }
                 } else if (pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN
                     && "emptyuser".equals(pc.getIdentifier())) {
                     pc.setPassword("");

Modified: webservices/wss4j/trunk/test/wssec/TestWSSecurityUTDK.java
URL: 
http://svn.apache.org/viewvc/webservices/wss4j/trunk/test/wssec/TestWSSecurityUTDK.java?rev=1032974&r1=1032973&r2=1032974&view=diff
==============================================================================
--- webservices/wss4j/trunk/test/wssec/TestWSSecurityUTDK.java (original)
+++ webservices/wss4j/trunk/test/wssec/TestWSSecurityUTDK.java Tue Nov  9 
12:52:16 2010
@@ -35,6 +35,7 @@ import org.apache.ws.security.message.WS
 import org.apache.ws.security.message.WSSecHeader;
 import org.apache.ws.security.message.WSSecUsernameToken;
 import org.apache.ws.security.message.token.UsernameToken;
+import org.apache.ws.security.util.Base64;
 import org.apache.ws.security.util.WSSecurityUtil;
 import org.w3c.dom.Document;
 
@@ -44,6 +45,8 @@ import javax.security.auth.callback.Unsu
 
 import java.io.IOException;
 
+import java.security.MessageDigest;
+import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -127,8 +130,25 @@ public class TestWSSecurityUTDK extends 
         byte[] derivedKey = UsernameToken.generateDerivedKey("security", salt, 
500);
         assertTrue(derivedKey.length == 20);
         
+        // "c2VjdXJpdHk=" is the Base64 encoding of "security"
+        derivedKey = 
UsernameToken.generateDerivedKey(Base64.decode("c2VjdXJpdHk="), salt, 500);
+        assertTrue(derivedKey.length == 20);
+    }
+
+    /**
+     * Test for encoded passwords.
+     */
+    public void testDerivedKeyWithEncodedPasswordBaseline() throws Exception {
+        String password = "password";
+        // The SHA-1 of the password is known as a password equivalent in the 
UsernameToken specification.
+        byte[] passwordHash = 
MessageDigest.getInstance("SHA-1").digest(password.getBytes("UTF-8"));
+
+        byte[] salt = Base64.decode("LKpycbfgRzwDnBz6kkhAAQ==");
+        int iteration = 1049;
+        byte[] expectedDerivedKey = 
Base64.decode("C7Ll/OY4TECb6hZuMMiX/5hzszo=");
+        byte[] derivedKey = UsernameToken.generateDerivedKey(passwordHash, 
salt, iteration);
+        assertTrue("the derived key is not as expected", 
Arrays.equals(expectedDerivedKey, derivedKey));
     }
-    
 
     /**
      * Test using a UsernameToken derived key for encrypting a SOAP body
@@ -173,6 +193,55 @@ public class TestWSSecurityUTDK extends 
     }
     
     /**
+     * Test using a UsernameToken derived key for encrypting a SOAP body
+     */
+    public void testDerivedKeyEncryptionWithEncodedPassword() throws Exception 
{
+        Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
+        WSSecHeader secHeader = new WSSecHeader();
+        secHeader.insertSecurityHeader(doc);
+        
+        WSSecUsernameToken builder = new WSSecUsernameToken();
+        builder.setPasswordsAreEncoded(true);
+        builder.setUserInfo("bob", 
Base64.encode(MessageDigest.getInstance("SHA-1").digest("security".getBytes("UTF-8"))));
+        builder.addDerivedKey(false, null, 1000);
+        builder.prepare(doc);
+        
+        byte[] derivedKey = builder.getDerivedKey();
+        assertTrue(derivedKey.length == 20);
+        
+        String tokenIdentifier = builder.getId();
+        
+        //
+        // Derived key encryption
+        //
+        WSSecDKEncrypt encrBuilder = new WSSecDKEncrypt();
+        encrBuilder.setSymmetricEncAlgorithm(WSConstants.AES_128);
+        encrBuilder.setExternalKey(derivedKey, tokenIdentifier);
+        Document encryptedDoc = encrBuilder.build(doc, secHeader);
+        
+        builder.prependToHeader(secHeader);
+        
+        String outputString = 
+            
org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(encryptedDoc);
+        assertTrue(outputString.indexOf("wsse:Username") != -1);
+        assertTrue(outputString.indexOf("wsse:Password") == -1);
+        assertTrue(outputString.indexOf("wsse11:Salt") != -1);
+        assertTrue(outputString.indexOf("wsse11:Iteration") != -1);
+        assertTrue(outputString.indexOf("testMethod") == -1);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(outputString);
+        }
+        
+        boolean passwordsAreEnabledOrig = 
WSSecurityEngine.getInstance().getWssConfig().getPasswordsAreEncoded();
+        try {
+            
WSSecurityEngine.getInstance().getWssConfig().setPasswordsAreEncoded(true);
+            verify(encryptedDoc);
+        } finally {
+            
WSSecurityEngine.getInstance().getWssConfig().setPasswordsAreEncoded(passwordsAreEnabledOrig);
+        }
+    }
+    
+    /**
      * Test using a UsernameToken derived key for encrypting a SOAP body. In 
this test the
      * derived key is modified before encryption, and so decryption should 
fail.
      */
@@ -319,6 +388,60 @@ public class TestWSSecurityUTDK extends 
     }
     
     /**
+     * Test using a UsernameToken derived key for signing a SOAP body
+     */
+    public void testDerivedKeySignatureWithEncodedPassword() throws Exception {
+        Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
+        WSSecHeader secHeader = new WSSecHeader();
+        secHeader.insertSecurityHeader(doc);
+        
+        WSSecUsernameToken builder = new WSSecUsernameToken();
+        builder.setPasswordsAreEncoded(true);
+        builder.setUserInfo("bob", 
Base64.encode(MessageDigest.getInstance("SHA-1").digest("security".getBytes("UTF-8"))));
+        builder.addDerivedKey(true, null, 1000);
+        builder.prepare(doc);
+        
+        byte[] derivedKey = builder.getDerivedKey();
+        assertTrue(derivedKey.length == 20);
+        
+        String tokenIdentifier = builder.getId();
+        
+        //
+        // Derived key signature
+        //
+        WSSecDKSign sigBuilder = new WSSecDKSign();
+        sigBuilder.setExternalKey(derivedKey, tokenIdentifier);
+        sigBuilder.setSignatureAlgorithm(WSConstants.HMAC_SHA1);
+        Document signedDoc = sigBuilder.build(doc, secHeader);
+        
+        builder.prependToHeader(secHeader);
+        
+        String outputString = 
+            
org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
+        assertTrue(outputString.indexOf("wsse:Username") != -1);
+        assertTrue(outputString.indexOf("wsse:Password") == -1);
+        assertTrue(outputString.indexOf("wsse11:Salt") != -1);
+        assertTrue(outputString.indexOf("wsse11:Iteration") != -1);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(outputString);
+        }
+        
+        boolean passwordsAreEnabledOrig = 
WSSecurityEngine.getInstance().getWssConfig().getPasswordsAreEncoded();
+        try {
+            
WSSecurityEngine.getInstance().getWssConfig().setPasswordsAreEncoded(true);
+            List results = verify(signedDoc);
+            WSSecurityEngineResult actionResult =
+                WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
+            java.security.Principal principal = 
+                (java.security.Principal) 
actionResult.get(WSSecurityEngineResult.TAG_PRINCIPAL);
+            // System.out.println(principal.getName());
+            assertTrue(principal.getName().indexOf("DK") != -1);
+        } finally {
+            
WSSecurityEngine.getInstance().getWssConfig().setPasswordsAreEncoded(passwordsAreEnabledOrig);
+        }
+    }
+    
+    /**
      * Test using a UsernameToken derived key for signing a SOAP body. In this 
test the
      * derived key is modified before signature, and so signature verification 
should
      * fail.
@@ -426,7 +549,12 @@ public class TestWSSecurityUTDK extends 
                 WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
                 if (pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN_UNKNOWN
                     && "bob".equals(pc.getIdentifier())) {
-                    pc.setPassword("security");
+                    if 
(WSSecurityEngine.getInstance().getWssConfig().getPasswordsAreEncoded()) {
+                        // "jux7xGGAjguKKHg9C+waOiLrCCE=" is the Base64 
encoded SHA-1 hash of "security".
+                        pc.setPassword("jux7xGGAjguKKHg9C+waOiLrCCE=");
+                    } else {
+                        pc.setPassword("security");
+                    }
                 } else {
                     throw new IOException("Authentication failed");
                 }



---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to