Author: coheigea
Date: Wed Dec 17 04:44:04 2008
New Revision: 727360
URL: http://svn.apache.org/viewvc?rev=727360&view=rev
Log:
[WSS-111] - Added support for verifying encryption/signature using keys derived
from a UsernameToken as per the UsernameToken 1.1 spec
- I think we can now say we fully support the UsernameToken 1.1 spec.
- Added a good few test-cases.
Modified:
webservices/wss4j/trunk/src/org/apache/ws/security/message/token/UsernameToken.java
webservices/wss4j/trunk/src/org/apache/ws/security/processor/DerivedKeyTokenProcessor.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
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=727360&r1=727359&r2=727360&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 Dec 17 04:44:04 2008
@@ -446,6 +446,13 @@
this.raw_password = raw_password;
}
+ /**
+ * Get the raw (plain text) password used to compute secret key.
+ */
+ public String getRawPassword() {
+ return this.raw_password;
+ }
+
public static String doPasswordDigest(String nonce, String created,
String password) {
String passwdDigest = null;
Modified:
webservices/wss4j/trunk/src/org/apache/ws/security/processor/DerivedKeyTokenProcessor.java
URL:
http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/processor/DerivedKeyTokenProcessor.java?rev=727360&r1=727359&r2=727360&view=diff
==============================================================================
---
webservices/wss4j/trunk/src/org/apache/ws/security/processor/DerivedKeyTokenProcessor.java
(original)
+++
webservices/wss4j/trunk/src/org/apache/ws/security/processor/DerivedKeyTokenProcessor.java
Wed Dec 17 04:44:04 2008
@@ -141,6 +141,8 @@
} else if (processor == null && keyIdentifierValue != null
&& keyIdentifierValueType != null) {
this.secret = this.getSecret(cb, keyIdentifierValue,
keyIdentifierValueType);
+ } else if (processor instanceof UsernameTokenProcessor) {
+ this.secret = ((UsernameTokenProcessor)
processor).getDerivedKey(cb);
} else if (processor instanceof EncryptedKeyProcessor) {
this.secret = ((EncryptedKeyProcessor) processor)
.getDecryptedBytes();
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=727360&r1=727359&r2=727360&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 Dec 17 04:44:04 2008
@@ -169,7 +169,8 @@
WSSecurityException.FAILED_AUTHENTICATION, null, null, e
);
}
- ut.setRawPassword(password);
+ origPassword = pwCb.getPassword();
+ ut.setRawPassword(origPassword);
}
WSUsernameTokenPrincipal principal = new
WSUsernameTokenPrincipal(user, ut.isHashed());
principal.setNonce(nonce);
@@ -195,4 +196,14 @@
public UsernameToken getUt() {
return ut;
}
+
+ public byte[] getDerivedKey(CallbackHandler cb) throws WSSecurityException
{
+ String password = ut.getRawPassword();
+ if (password == null) {
+ password = "";
+ }
+ byte[] saltValue = ut.getSalt();
+ int iteration = ut.getIteration();
+ 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=727360&r1=727359&r2=727360&view=diff
==============================================================================
--- webservices/wss4j/trunk/test/wssec/TestWSSecurityNew5.java (original)
+++ webservices/wss4j/trunk/test/wssec/TestWSSecurityNew5.java Wed Dec 17
04:44:04 2008
@@ -310,6 +310,32 @@
}
/**
+ * Test that adds a UserNameToken with no password
+ */
+ public void testUsernameTokenNoPassword() throws Exception {
+ WSSecUsernameToken builder = new WSSecUsernameToken();
+ builder.setPasswordType(null);
+ builder.setUserInfo("wernerd", null);
+ log.info("Before adding UsernameToken with no password....");
+ Document doc = unsignedEnvelope.getAsDocument();
+ WSSecHeader secHeader = new WSSecHeader();
+ secHeader.insertSecurityHeader(doc);
+ Document signedDoc = builder.build(doc, secHeader);
+ Message signedMsg = SOAPUtil.toAxisMessage(signedDoc);
+ if (log.isDebugEnabled()) {
+
XMLUtils.PrettyElementToWriter(signedMsg.getSOAPEnvelope().getAsDOM(), new
PrintWriter(System.out));
+ }
+ signedDoc = signedMsg.getSOAPEnvelope().getAsDocument();
+ try {
+ verify(signedDoc);
+ throw new Exception("Failure expected on no password");
+ } catch (WSSecurityException ex) {
+ assertTrue(ex.getErrorCode() ==
WSSecurityException.FAILED_AUTHENTICATION);
+ // expected
+ }
+ }
+
+ /**
* Test with a null token type. This will fail as the default is to reject
custom
* token types.
* <p/>
Modified: webservices/wss4j/trunk/test/wssec/TestWSSecurityUTDK.java
URL:
http://svn.apache.org/viewvc/webservices/wss4j/trunk/test/wssec/TestWSSecurityUTDK.java?rev=727360&r1=727359&r2=727360&view=diff
==============================================================================
--- webservices/wss4j/trunk/test/wssec/TestWSSecurityUTDK.java (original)
+++ webservices/wss4j/trunk/test/wssec/TestWSSecurityUTDK.java Wed Dec 17
04:44:04 2008
@@ -28,6 +28,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ws.security.WSConstants;
+import org.apache.ws.security.WSSecurityEngineResult;
import org.apache.ws.security.WSSecurityException;
import org.apache.ws.security.WSPasswordCallback;
import org.apache.ws.security.WSSecurityEngine;
@@ -62,8 +63,8 @@
/**
* WS-Security Test Case for UsernameToken Key Derivation, as defined in the
- * UsernameTokenProfile 1.1 specification. Note that the processing of
UsernameTokens
- * with derived keys is not yet supported.
+ * UsernameTokenProfile 1.1 specification. The derived keys are used to encrypt
+ * and sign, as per wsc:DerivedKeyToken.
*/
public class TestWSSecurityUTDK extends TestCase implements CallbackHandler {
private static Log log = LogFactory.getLog(TestWSSecurityUTDK.class);
@@ -209,11 +210,111 @@
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);
}
- // verify(encryptedDoc);
+ verify(encryptedDoc);
+ }
+
+ /**
+ * 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.
+ */
+ public void testDerivedKeyChangedEncryption() throws Exception {
+ Document doc = unsignedEnvelope.getAsDocument();
+ WSSecHeader secHeader = new WSSecHeader();
+ secHeader.insertSecurityHeader(doc);
+
+ WSSecUsernameToken builder = new WSSecUsernameToken();
+ builder.setUserInfo("bob", "security");
+ builder.addDerivedKey(false, null, 1000);
+ builder.prepare(doc);
+
+ byte[] derivedKey = builder.getDerivedKey();
+ derivedKey[5] = 12;
+ 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);
+ }
+
+ try {
+ verify(encryptedDoc);
+ throw new Exception("Failure expected on a bad derived
encryption");
+ } catch (WSSecurityException ex) {
+ assertTrue(ex.getErrorCode() == WSSecurityException.FAILED_CHECK);
+ // expected
+ }
+ }
+
+ /**
+ * Test using a UsernameToken derived key for encrypting a SOAP body. In
this test the
+ * user is "alice" rather than "bob", and so decryption should fail.
+ */
+ public void testDerivedKeyBadUserEncryption() throws Exception {
+ Document doc = unsignedEnvelope.getAsDocument();
+ WSSecHeader secHeader = new WSSecHeader();
+ secHeader.insertSecurityHeader(doc);
+
+ WSSecUsernameToken builder = new WSSecUsernameToken();
+ builder.setUserInfo("alice", "security");
+ 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);
+ }
+
+ try {
+ verify(encryptedDoc);
+ throw new Exception("Failure expected on a bad derived
encryption");
+ } catch (WSSecurityException ex) {
+ assertTrue(ex.getErrorCode() ==
WSSecurityException.FAILED_AUTHENTICATION);
+ // expected
+ }
}
/**
@@ -254,7 +355,103 @@
log.debug(outputString);
}
- // verify(signedDoc);
+ 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);
+ }
+
+ /**
+ * 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.
+ */
+ public void testDerivedKeyChangedSignature() throws Exception {
+ Document doc = unsignedEnvelope.getAsDocument();
+ WSSecHeader secHeader = new WSSecHeader();
+ secHeader.insertSecurityHeader(doc);
+
+ WSSecUsernameToken builder = new WSSecUsernameToken();
+ builder.setUserInfo("bob", "security");
+ builder.addDerivedKey(true, null, 1000);
+ builder.prepare(doc);
+
+ byte[] derivedKey = builder.getDerivedKey();
+ derivedKey[5] = 12;
+ assertTrue(derivedKey.length == 20);
+
+ String tokenIdentifier = builder.getId();
+
+ //
+ // Derived key encryption
+ //
+ 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);
+ if (log.isDebugEnabled()) {
+ log.debug(outputString);
+ }
+
+ try {
+ verify(signedDoc);
+ throw new Exception("Failure expected on a bad derived signature");
+ } catch (WSSecurityException ex) {
+ assertTrue(ex.getErrorCode() == WSSecurityException.FAILED_CHECK);
+ // expected
+ }
+ }
+
+ /**
+ * Test using a UsernameToken derived key for signing a SOAP body. In this
test the
+ * user is "alice" rather than "bob", and so signature verification should
fail.
+ */
+ public void testDerivedKeyBadUserSignature() throws Exception {
+ Document doc = unsignedEnvelope.getAsDocument();
+ WSSecHeader secHeader = new WSSecHeader();
+ secHeader.insertSecurityHeader(doc);
+
+ WSSecUsernameToken builder = new WSSecUsernameToken();
+ builder.setUserInfo("alice", "security");
+ builder.addDerivedKey(true, null, 1000);
+ builder.prepare(doc);
+
+ byte[] derivedKey = builder.getDerivedKey();
+ assertTrue(derivedKey.length == 20);
+
+ String tokenIdentifier = builder.getId();
+
+ //
+ // Derived key encryption
+ //
+ 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);
+ if (log.isDebugEnabled()) {
+ log.debug(outputString);
+ }
+
+ try {
+ verify(signedDoc);
+ throw new Exception("Failure expected on a bad derived signature");
+ } catch (WSSecurityException ex) {
+ assertTrue(ex.getErrorCode() ==
WSSecurityException.FAILED_AUTHENTICATION);
+ // expected
+ }
}
/**
@@ -263,8 +460,8 @@
* @param env soap envelope
* @throws java.lang.Exception Thrown when there is a problem in
verification
*/
- private void verify(Document doc) throws Exception {
- secEngine.processSecurityHeader(doc, null, this, crypto);
+ private Vector verify(Document doc) throws Exception {
+ return secEngine.processSecurityHeader(doc, null, this, crypto);
}
@@ -272,9 +469,13 @@
throws IOException, UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
if (callbacks[i] instanceof WSPasswordCallback) {
- //
- // Do nothing
- //
+ WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
+ if (pc.getUsage() == WSPasswordCallback.USERNAME_TOKEN_UNKNOWN
+ && "bob".equals(pc.getIdentifier())) {
+ pc.setPassword("security");
+ } else {
+ throw new IOException("Authentication failed");
+ }
} else {
throw new UnsupportedCallbackException(callbacks[i],
"Unrecognized Callback");
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]