You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ws.apache.org by co...@apache.org on 2010/11/09 12:43:11 UTC
svn commit: r1032939 - in /webservices/wss4j/branches/1_5_x-fixes:
src/org/apache/ws/security/ src/org/apache/ws/security/action/
src/org/apache/ws/security/handler/ src/org/apache/ws/security/message/
src/org/apache/ws/security/message/token/ src/org/...
Author: coheigea
Date: Tue Nov 9 11:43:11 2010
New Revision: 1032939
URL: http://svn.apache.org/viewvc?rev=1032939&view=rev
Log:
[WSS-239] - Need ability to handle password "equivalent" between WSPasswordCallback and UsernameToken when it's binary data
Modified:
webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/WSSConfig.java
webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/action/UsernameTokenAction.java
webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/handler/WSHandler.java
webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/handler/WSHandlerConstants.java
webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/message/WSSecUsernameToken.java
webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/message/token/UsernameToken.java
webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/processor/UsernameTokenProcessor.java
webservices/wss4j/branches/1_5_x-fixes/test/wssec/TestWSSecurityNew5.java
webservices/wss4j/branches/1_5_x-fixes/test/wssec/TestWSSecurityUTDK.java
Modified: webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/WSSConfig.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/WSSConfig.java?rev=1032939&r1=1032938&r2=1032939&view=diff
==============================================================================
--- webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/WSSConfig.java (original)
+++ webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/WSSConfig.java Tue Nov 9 11:43:11 2010
@@ -212,6 +212,18 @@ public class WSSConfig {
*/
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"
@@ -446,6 +458,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/branches/1_5_x-fixes/src/org/apache/ws/security/action/UsernameTokenAction.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/action/UsernameTokenAction.java?rev=1032939&r1=1032938&r2=1032939&view=diff
==============================================================================
--- webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/action/UsernameTokenAction.java (original)
+++ webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/action/UsernameTokenAction.java Tue Nov 9 11:43:11 2010
@@ -43,6 +43,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/branches/1_5_x-fixes/src/org/apache/ws/security/handler/WSHandler.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/handler/WSHandler.java?rev=1032939&r1=1032938&r2=1032939&view=diff
==============================================================================
--- webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/handler/WSHandler.java (original)
+++ webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/handler/WSHandler.java Tue Nov 9 11:43:11 2010
@@ -100,6 +100,7 @@ public abstract class WSHandler {
wssConfig.setEnableSignatureConfirmation(
enableSigConf || ((doAction & WSConstants.SC) != 0)
);
+ wssConfig.setPasswordsAreEncoded(decodeUseEncodedPasswords(reqData));
wssConfig.setPrecisionInMilliSeconds(
decodeTimestampPrecision(reqData)
@@ -263,6 +264,7 @@ public abstract class WSHandler {
);
wssConfig.setTimeStampStrict(decodeTimestampStrict(reqData));
wssConfig.setHandleCustomPasswordTypes(decodeCustomPasswordTypes(reqData));
+ wssConfig.setPasswordsAreEncoded(decodeUseEncodedPasswords(reqData));
wssConfig.setAllowNamespaceQualifiedPasswordTypes(
decodeNamespaceQualifiedPasswordTypes(reqData)
);
@@ -763,6 +765,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/branches/1_5_x-fixes/src/org/apache/ws/security/handler/WSHandlerConstants.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/handler/WSHandlerConstants.java?rev=1032939&r1=1032938&r2=1032939&view=diff
==============================================================================
--- webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/handler/WSHandlerConstants.java (original)
+++ webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/handler/WSHandlerConstants.java Tue Nov 9 11:43:11 2010
@@ -800,6 +800,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/branches/1_5_x-fixes/src/org/apache/ws/security/message/WSSecUsernameToken.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/message/WSSecUsernameToken.java?rev=1032939&r1=1032938&r2=1032939&view=diff
==============================================================================
--- webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/message/WSSecUsernameToken.java (original)
+++ webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/message/WSSecUsernameToken.java Tue Nov 9 11:43:11 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;
@@ -48,6 +49,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;
/**
* Constructor.
@@ -130,7 +132,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);
}
@@ -149,7 +155,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;
}
/**
@@ -180,6 +205,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/branches/1_5_x-fixes/src/org/apache/ws/security/message/token/UsernameToken.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/message/token/UsernameToken.java?rev=1032939&r1=1032938&r2=1032939&view=diff
==============================================================================
--- webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/message/token/UsernameToken.java (original)
+++ webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/message/token/UsernameToken.java Tue Nov 9 11:43:11 2010
@@ -73,6 +73,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 {
@@ -453,7 +454,11 @@ public class UsernameToken {
node.setData(pwd);
elementPassword.setAttributeNS(null, "Type", WSConstants.PASSWORD_TEXT);
} else {
- node.setData(doPasswordDigest(getNonce(), getCreated(), pwd));
+ if (passwordsAreEncoded) {
+ node.setData(doPasswordDigest(getNonce(), getCreated(), Base64.decode(pwd)));
+ } else {
+ node.setData(doPasswordDigest(getNonce(), getCreated(), pwd));
+ }
elementPassword.setAttributeNS(null, "Type", WSConstants.PASSWORD_DIGEST);
}
} catch (Exception e) {
@@ -479,12 +484,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);
@@ -507,6 +526,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.
*
@@ -613,7 +644,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");
@@ -647,7 +683,7 @@ public class UsernameToken {
return key;
}
-
+
/**
* This static method generates a derived key as defined in WSS Username
* Token Profile.
@@ -660,26 +696,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 {
@@ -707,6 +734,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.
@@ -717,7 +770,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/branches/1_5_x-fixes/src/org/apache/ws/security/processor/UsernameTokenProcessor.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/processor/UsernameTokenProcessor.java?rev=1032939&r1=1032938&r2=1032939&view=diff
==============================================================================
--- webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/processor/UsernameTokenProcessor.java (original)
+++ webservices/wss4j/branches/1_5_x-fixes/src/org/apache/ws/security/processor/UsernameTokenProcessor.java Tue Nov 9 11:43:11 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, Vector 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((Element) elem, cb);
returnResults.add(
@@ -91,6 +94,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();
@@ -140,7 +144,12 @@ public class UsernameTokenProcessor impl
}
throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
}
- 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);
}
@@ -210,6 +219,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/branches/1_5_x-fixes/test/wssec/TestWSSecurityNew5.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/branches/1_5_x-fixes/test/wssec/TestWSSecurityNew5.java?rev=1032939&r1=1032938&r2=1032939&view=diff
==============================================================================
--- webservices/wss4j/branches/1_5_x-fixes/test/wssec/TestWSSecurityNew5.java (original)
+++ webservices/wss4j/branches/1_5_x-fixes/test/wssec/TestWSSecurityNew5.java Tue Nov 9 11:43:11 2010
@@ -38,6 +38,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;
@@ -48,6 +49,7 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
+import java.util.Arrays;
/**
@@ -174,6 +176,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 = unsignedEnvelope.getAsDocument();
+ 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.
*/
@@ -633,26 +680,53 @@ 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("");
+ if (passwordsAreEncoded) {
+ // "2jmj7l5rSw0yVb/vlWAYkK/YBwk=" is the Base64 encoded SHA-1 hash of "".
+ pc.setPassword("2jmj7l5rSw0yVb/vlWAYkK/YBwk=");
+ } else {
+ pc.setPassword("");
+ }
}
else if (
pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN_UNKNOWN
) {
- if ("wernerd".equals(pc.getIdentifier())
- && "verySecret".equals(pc.getPassword())) {
- return;
- } else if ("customUser".equals(pc.getIdentifier())) {
- return;
- } else if ("wernerd".equals(pc.getIdentifier())
- && "".equals(pc.getPassword())) {
- return;
+ if (passwordsAreEncoded) {
+ if ("wernerd".equals(pc.getIdentifier())
+ && "hGqoUreBgahTJblQ3DbJIkE6uNs=".equals(pc.getPassword())) {
+ // "hGqoUreBgahTJblQ3DbJIkE6uNs=" is the Base64 encoded SHA-1 hash of "verySecret".
+ return;
+ } else if ("customUser".equals(pc.getIdentifier())) {
+ return;
+ } else if ("wernerd".equals(pc.getIdentifier())
+ && "2jmj7l5rSw0yVb/vlWAYkK/YBwk=".equals(pc.getPassword())) {
+ // "2jmj7l5rSw0yVb/vlWAYkK/YBwk=" is the Base64 encoded SHA-1 hash of "".
+ return;
+ } else {
+ throw new IOException("Authentication failed");
+ }
} else {
- throw new IOException("Authentication failed");
+ if ("wernerd".equals(pc.getIdentifier())
+ && "verySecret".equals(pc.getPassword())) {
+ return;
+ } else if ("customUser".equals(pc.getIdentifier())) {
+ return;
+ } else if ("wernerd".equals(pc.getIdentifier())
+ && "".equals(pc.getPassword())) {
+ return;
+ } else {
+ throw new IOException("Authentication failed");
+ }
}
}
} else {
Modified: webservices/wss4j/branches/1_5_x-fixes/test/wssec/TestWSSecurityUTDK.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/branches/1_5_x-fixes/test/wssec/TestWSSecurityUTDK.java?rev=1032939&r1=1032938&r2=1032939&view=diff
==============================================================================
--- webservices/wss4j/branches/1_5_x-fixes/test/wssec/TestWSSecurityUTDK.java (original)
+++ webservices/wss4j/branches/1_5_x-fixes/test/wssec/TestWSSecurityUTDK.java Tue Nov 9 11:43:11 2010
@@ -41,6 +41,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.apache.xml.security.signature.XMLSignature;
import org.w3c.dom.Document;
@@ -53,6 +54,8 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.security.MessageDigest;
+import java.util.Arrays;
import java.util.Vector;
/**
@@ -163,8 +166,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
@@ -209,6 +229,55 @@ public class TestWSSecurityUTDK extends
}
/**
+ * Test using a UsernameToken derived key for encrypting a SOAP body
+ */
+ public void testDerivedKeyEncryptionWithEncodedPassword() throws Exception {
+ Document doc = unsignedEnvelope.getAsDocument();
+ 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.
*/
@@ -355,6 +424,60 @@ public class TestWSSecurityUTDK extends
}
/**
+ * Test using a UsernameToken derived key for signing a SOAP body
+ */
+ public void testDerivedKeySignatureWithEncodedPassword() throws Exception {
+ Document doc = unsignedEnvelope.getAsDocument();
+ 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(XMLSignature.ALGO_ID_MAC_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);
+ Vector 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("derivedKey") != -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.
@@ -462,7 +585,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: dev-unsubscribe@ws.apache.org
For additional commands, e-mail: dev-help@ws.apache.org