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]

Reply via email to