You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ws.apache.org by co...@apache.org on 2011/01/24 14:15:51 UTC

svn commit: r1062763 - in /webservices/wss4j/trunk/src: main/java/org/apache/ws/security/ main/java/org/apache/ws/security/components/crypto/ main/java/org/apache/ws/security/processor/ main/java/org/apache/ws/security/saml/ext/ main/java/org/apache/ws...

Author: coheigea
Date: Mon Jan 24 13:15:50 2011
New Revision: 1062763

URL: http://svn.apache.org/viewvc?rev=1062763&view=rev
Log:
[WSS-266] - A first cut at this issue
 - Added a set of Validators for signature trust verification, username token authentication, and Timestamp validation
 - Removed PublicKeyCallback - this is now done as part of Crypto

Added:
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/Credential.java
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/SignatureTrustValidator.java
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/TimestampValidator.java
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/UsernameTokenValidator.java
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/Validator.java
Removed:
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/PublicKeyCallback.java
    webservices/wss4j/trunk/src/test/java/org/apache/ws/security/common/PublicKeyCallbackHandler.java
Modified:
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/components/crypto/Crypto.java
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/components/crypto/CryptoBase.java
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/SAMLTokenProcessor.java
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/SignatureProcessor.java
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/TimestampProcessor.java
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/UsernameTokenProcessor.java
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/saml/ext/AssertionWrapper.java
    webservices/wss4j/trunk/src/test/java/org/apache/ws/security/common/KeystoreCallbackHandler.java
    webservices/wss4j/trunk/src/test/java/org/apache/ws/security/message/SignatureKeyValueTest.java
    webservices/wss4j/trunk/src/test/java/org/apache/ws/security/saml/SamlTokenHOKTest.java
    webservices/wss4j/trunk/src/test/java/org/apache/ws/security/saml/SignedSamlTokenHOKTest.java

Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/components/crypto/Crypto.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/components/crypto/Crypto.java?rev=1062763&r1=1062762&r2=1062763&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/components/crypto/Crypto.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/components/crypto/Crypto.java Mon Jan 24 13:15:50 2011
@@ -24,6 +24,7 @@ import java.io.InputStream;
 import java.math.BigInteger;
 import java.security.KeyStore;
 import java.security.PrivateKey;
+import java.security.PublicKey;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
@@ -268,6 +269,15 @@ public interface Crypto {
      * @throws WSSecurityException
      */
     public boolean validateCertPath(X509Certificate[] certs) throws WSSecurityException;
+    
+    /**
+     * Evaluate whether a given public key should be trusted.
+     * Essentially, this amounts to checking to see if there is a certificate in the keystore
+     * or truststore, whose public key matches the transmitted public key.
+     * @param publicKey The PublicKey to be evaluated
+     * @return whether the PublicKey parameter is trusted or not
+     */
+    public boolean verifyTrust(PublicKey publicKey) throws WSSecurityException;
 
     /**
      * Lookup X509 Certificates in the keystore according to a given DN of the subject of the certificate

Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/components/crypto/CryptoBase.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/components/crypto/CryptoBase.java?rev=1062763&r1=1062762&r2=1062763&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/components/crypto/CryptoBase.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/components/crypto/CryptoBase.java Mon Jan 24 13:15:50 2011
@@ -995,6 +995,71 @@ public abstract class CryptoBase impleme
     }
     
     /**
+     * Evaluate whether a given public key should be trusted.
+     * Essentially, this amounts to checking to see if there is a certificate in the keystore
+     * or truststore, whose public key matches the transmitted public key.
+     * @param publicKey The PublicKey to be evaluated
+     * @return whether the PublicKey parameter is trusted or not
+     */
+    public boolean verifyTrust(PublicKey publicKey) throws WSSecurityException {
+        //
+        // If the public key is null, do not trust the signature
+        //
+        if (publicKey == null) {
+            return false;
+        }
+        
+        //
+        // Search the keystore for the transmitted public key (direct trust)
+        //
+        boolean trust = findPublicKeyInKeyStore(publicKey, keystore);
+        if (trust) {
+            return true;
+        } else {
+            //
+            // Now search the truststore for the transmitted public key (direct trust)
+            //
+            trust = findPublicKeyInKeyStore(publicKey, truststore);
+            if (trust) {
+                return true;
+            }
+        }
+        return false;
+    }
+    
+    /**
+     * Find the Public Key in a keystore. 
+     */
+    private boolean findPublicKeyInKeyStore(PublicKey publicKey, KeyStore keyStoreToSearch) {
+        try {
+            for (Enumeration<String> e = keyStoreToSearch.aliases(); e.hasMoreElements();) {
+                String alias = e.nextElement();
+                Certificate[] certs = keyStoreToSearch.getCertificateChain(alias);
+                Certificate cert;
+                if (certs == null || certs.length == 0) {
+                    // no cert chain, so lets check if getCertificate gives us a result.
+                    cert = keyStoreToSearch.getCertificate(alias);
+                    if (cert == null) {
+                        continue;
+                    }
+                } else {
+                    cert = certs[0];
+                }
+                if (!(cert instanceof X509Certificate)) {
+                    continue;
+                }
+                X509Certificate x509cert = (X509Certificate) cert;
+                if (publicKey.equals(x509cert.getPublicKey())) {
+                    return true;
+                }
+            }
+        } catch (KeyStoreException e) {
+            return false;
+        }
+        return false;
+    }
+    
+    /**
      * Get all of the aliases of the X500Principal argument in the supplied KeyStore
      * @param subjectRDN either an X500Principal or a BouncyCastle X509Name instance.
      * @param store The KeyStore

Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/SAMLTokenProcessor.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/SAMLTokenProcessor.java?rev=1062763&r1=1062762&r2=1062763&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/SAMLTokenProcessor.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/SAMLTokenProcessor.java Mon Jan 24 13:15:50 2011
@@ -27,8 +27,12 @@ import org.apache.ws.security.WSSConfig;
 import org.apache.ws.security.WSSecurityEngineResult;
 import org.apache.ws.security.WSSecurityException;
 import org.apache.ws.security.components.crypto.Crypto;
+import org.apache.ws.security.saml.SAMLKeyInfo;
 import org.apache.ws.security.saml.ext.AssertionWrapper;
 import org.apache.ws.security.util.DOM2Writer;
+import org.apache.ws.security.validate.Credential;
+import org.apache.ws.security.validate.SignatureTrustValidator;
+import org.apache.ws.security.validate.Validator;
 
 import org.w3c.dom.Element;
 
@@ -38,6 +42,8 @@ import javax.security.auth.callback.Call
 public class SAMLTokenProcessor implements Processor {
     private static Log log = LogFactory.getLog(SAMLTokenProcessor.class.getName());
     
+    private Validator validator = new SignatureTrustValidator();
+    
     public List<WSSecurityEngineResult> handleToken(
         Element elem, 
         Crypto crypto,
@@ -69,12 +75,20 @@ public class SAMLTokenProcessor implemen
     ) throws WSSecurityException {
         AssertionWrapper assertion = new AssertionWrapper(token);
         if (assertion.isSigned()) {
-            assertion.verify(crypto);
+            SAMLKeyInfo samlKeyInfo = assertion.verify(crypto);
+            
+            // Now verify trust on the signature credential
+            validator.setCrypto(crypto);
+            Credential credential = new Credential();
+            credential.setPublicKey(samlKeyInfo.getPublicKey());
+            credential.setCertificates(samlKeyInfo.getCerts());
+            validator.validate(credential);
         }
         if (log.isDebugEnabled()) {
             log.debug("SAML Assertion issuer " + assertion.getIssuerString());
             log.debug(DOM2Writer.nodeToString(token));
         }
+        
         return assertion;
     }
 

Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/SignatureProcessor.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/SignatureProcessor.java?rev=1062763&r1=1062762&r2=1062763&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/SignatureProcessor.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/SignatureProcessor.java Mon Jan 24 13:15:50 2011
@@ -21,7 +21,6 @@ package org.apache.ws.security.processor
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.apache.ws.security.PublicKeyCallback;
 import org.apache.ws.security.PublicKeyPrincipal;
 import org.apache.ws.security.WSConstants;
 import org.apache.ws.security.WSDataRef;
@@ -38,12 +37,14 @@ import org.apache.ws.security.str.Signat
 import org.apache.ws.security.transform.STRTransform;
 import org.apache.ws.security.transform.STRTransformUtil;
 import org.apache.ws.security.util.WSSecurityUtil;
+import org.apache.ws.security.validate.Credential;
+import org.apache.ws.security.validate.SignatureTrustValidator;
+import org.apache.ws.security.validate.Validator;
 
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 
-import javax.security.auth.callback.Callback;
 import javax.security.auth.callback.CallbackHandler;
 
 import javax.xml.crypto.MarshalException;
@@ -62,12 +63,9 @@ import javax.xml.crypto.dsig.keyinfo.Key
 import javax.xml.crypto.dsig.keyinfo.KeyInfoFactory;
 import javax.xml.crypto.dsig.keyinfo.KeyValue;
 
-import java.math.BigInteger;
 import java.security.Key;
 import java.security.PublicKey;
 import java.security.Principal;
-import java.security.cert.CertificateExpiredException;
-import java.security.cert.CertificateNotYetValidException;
 import java.security.cert.X509Certificate;
 import java.util.HashMap;
 import java.util.List;
@@ -79,7 +77,8 @@ public class SignatureProcessor implemen
     private XMLSignatureFactory signatureFactory = XMLSignatureFactory.getInstance("DOM");
     
     private KeyInfoFactory keyInfoFactory = KeyInfoFactory.getInstance("DOM");
-
+    private Validator validator = new SignatureTrustValidator();
+    
     public List<WSSecurityEngineResult> handleToken(
         Element elem, 
         Crypto crypto, 
@@ -102,6 +101,9 @@ public class SignatureProcessor implemen
         PublicKey publicKey = null;
         byte[] secretKey = null;
         String signatureMethod = getSignatureMethod(elem);
+
+        validator.setCrypto(crypto);
+        
         if (keyInfoElement == null) {
             certs = getDefaultCerts(crypto);
             principal = certs[0].getSubjectX500Principal();
@@ -114,7 +116,10 @@ public class SignatureProcessor implemen
                 );
             if (strElement == null) {
                 publicKey = parseKeyValue(keyInfoElement);
-                principal = validatePublicKey(cb, publicKey);
+                Credential credential = new Credential();
+                credential.setPublicKey(publicKey);
+                validator.validate(credential);
+                principal = new PublicKeyPrincipal(publicKey);
             } else {
                 STRParser strParser = new SignatureSTRParser();
                 Map<String, Object> parameters = new HashMap<String, Object>();
@@ -129,7 +134,12 @@ public class SignatureProcessor implemen
                 certs = strParser.getCertificates();
                 publicKey = strParser.getPublicKey();
                 secretKey = strParser.getSecretKey();
-                validateCredentials(certs, crypto);
+                if (certs != null || publicKey != null) {
+                    Credential credential = new Credential();
+                    credential.setPublicKey(publicKey);
+                    credential.setCertificates(certs);
+                    validator.validate(credential);
+                }
             }
         }
         
@@ -189,214 +199,6 @@ public class SignatureProcessor implemen
         }
     }
     
-    /**
-     * Validate the credentials that were extracted from the SecurityTokenReference
-     * TODO move into Validator
-     * @throws WSSecurityException if the credentials are invalid
-     */
-    private void validateCredentials(
-        X509Certificate[] certs,
-        Crypto crypto
-    ) throws WSSecurityException {
-        //
-        // Validate certificates and verify trust
-        //
-        validateCertificates(certs);
-        if (certs != null) {
-            boolean trust = false;
-            if (certs.length == 1) {
-                trust = verifyTrust(certs[0], crypto);
-            } else if (certs.length > 1) {
-                trust = verifyTrust(certs, crypto);
-            }
-            if (!trust) {
-                throw new WSSecurityException(WSSecurityException.FAILED_CHECK);
-            }
-        }
-    }
-    
-    /**
-     * Validate an array of certificates by checking the validity of each cert
-     * @param certsToValidate The array of certificates to validate
-     * @throws WSSecurityException
-     */
-    private static void validateCertificates(
-        X509Certificate[] certsToValidate
-    ) throws WSSecurityException {
-        if (certsToValidate != null && certsToValidate.length > 0) {
-            try {
-                for (int i = 0; i < certsToValidate.length; i++) {
-                    certsToValidate[i].checkValidity();
-                }
-            } catch (CertificateExpiredException e) {
-                throw new WSSecurityException(
-                    WSSecurityException.FAILED_CHECK, "invalidCert", null, e
-                );
-            } catch (CertificateNotYetValidException e) {
-                throw new WSSecurityException(
-                    WSSecurityException.FAILED_CHECK, "invalidCert", null, e
-                );
-            }
-        }
-    }
-    
-    
-    /**
-     * Evaluate whether a given certificate should be trusted.
-     * 
-     * Policy used in this implementation:
-     * 1. Search the keystore for the transmitted certificate
-     * 2. Search the keystore for a connection to the transmitted certificate
-     * (that is, search for certificate(s) of the issuer of the transmitted certificate
-     * 3. Verify the trust path for those certificates found because the search for the issuer 
-     * might be fooled by a phony DN (String!)
-     *
-     * @param cert the certificate that should be validated against the keystore
-     * @return true if the certificate is trusted, false if not
-     * @throws WSSecurityException
-     */
-    private static boolean verifyTrust(X509Certificate cert, Crypto crypto) 
-        throws WSSecurityException {
-
-        // If no certificate was transmitted, do not trust the signature
-        if (cert == null) {
-            return false;
-        }
-
-        String subjectString = cert.getSubjectX500Principal().getName();
-        String issuerString = cert.getIssuerX500Principal().getName();
-        BigInteger issuerSerial = cert.getSerialNumber();
-
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("Transmitted certificate has subject " + subjectString);
-            LOG.debug(
-                "Transmitted certificate has issuer " + issuerString + " (serial " 
-                + issuerSerial + ")"
-            );
-        }
-
-        //
-        // FIRST step - Search the keystore for the transmitted certificate
-        //
-        if (crypto.isCertificateInKeyStore(cert)) {
-            return true;
-        }
-
-        //
-        // SECOND step - Search for the issuer of the transmitted certificate in the 
-        // keystore or the truststore
-        //
-        String[] aliases = crypto.getAliasesForDN(issuerString);
-
-        // If the alias has not been found, the issuer is not in the keystore/truststore
-        // As a direct result, do not trust the transmitted certificate
-        if (aliases == null || aliases.length < 1) {
-            if (LOG.isDebugEnabled()) {
-                LOG.debug(
-                    "No aliases found in keystore for issuer " + issuerString 
-                    + " of certificate for " + subjectString
-                );
-            }
-            return false;
-        }
-
-        //
-        // THIRD step
-        // Check the certificate trust path for every alias of the issuer found in the 
-        // keystore/truststore
-        //
-        for (int i = 0; i < aliases.length; i++) {
-            String alias = aliases[i];
-
-            if (LOG.isDebugEnabled()) {
-                LOG.debug(
-                    "Preparing to validate certificate path with alias " + alias 
-                    + " for issuer " + issuerString
-                );
-            }
-
-            // Retrieve the certificate(s) for the alias from the keystore/truststore
-            X509Certificate[] certs = crypto.getCertificates(alias);
-
-            // If no certificates have been found, there has to be an error:
-            // The keystore/truststore can find an alias but no certificate(s)
-            if (certs == null || certs.length < 1) {
-                throw new WSSecurityException(
-                    "Could not get certificates for alias " + alias
-                );
-            }
-
-            //
-            // Form a certificate chain from the transmitted certificate
-            // and the certificate(s) of the issuer from the keystore/truststore
-            //
-            X509Certificate[] x509certs = new X509Certificate[certs.length + 1];
-            x509certs[0] = cert;
-            for (int j = 0; j < certs.length; j++) {
-                x509certs[j + 1] = certs[j];
-            }
-
-            //
-            // Use the validation method from the crypto to check whether the subjects' 
-            // certificate was really signed by the issuer stated in the certificate
-            //
-            if (crypto.validateCertPath(x509certs)) {
-                if (LOG.isDebugEnabled()) {
-                    LOG.debug(
-                        "Certificate path has been verified for certificate with subject " 
-                        + subjectString
-                    );
-                }
-                return true;
-            }
-        }
-
-        if (LOG.isDebugEnabled()) {
-            LOG.debug(
-                "Certificate path could not be verified for certificate with subject " 
-                + subjectString
-            );
-        }
-        return false;
-    }
-    
-
-    /**
-     * Evaluate whether the given certificate chain should be trusted.
-     * 
-     * @param certificates the certificate chain that should be validated against the keystore
-     * @return true if the certificate chain is trusted, false if not
-     * @throws WSSecurityException
-     */
-    private static boolean verifyTrust(X509Certificate[] certificates, Crypto crypto) 
-        throws WSSecurityException {
-        String subjectString = certificates[0].getSubjectX500Principal().getName();
-        //
-        // Use the validation method from the crypto to check whether the subjects' 
-        // certificate was really signed by the issuer stated in the certificate
-        //
-        if (certificates != null && certificates.length > 1
-            && crypto.validateCertPath(certificates)) {
-            if (LOG.isDebugEnabled()) {
-                LOG.debug(
-                    "Certificate path has been verified for certificate with subject " 
-                    + subjectString
-                );
-            }
-            return true;
-        }
-        
-        if (LOG.isDebugEnabled()) {
-            LOG.debug(
-                "Certificate path could not be verified for certificate with subject " 
-                + subjectString
-            );
-        }
-            
-        return false;
-    }
-    
-    
     private PublicKey parseKeyValue(
         Element keyInfoElement
     ) throws WSSecurityException {
@@ -446,36 +248,6 @@ public class SignatureProcessor implemen
         return null;
     }
     
-    /**
-     * Validate a public key via a CallbackHandler
-     * @param cb The CallbackHandler object
-     * @param publicKey The PublicKey to validate
-     * @return A PublicKeyPrincipal object encapsulating the public key after successful 
-     *         validation
-     * @throws WSSecurityException
-     */
-    private static Principal validatePublicKey(
-        CallbackHandler cb,
-        PublicKey publicKey
-    ) throws WSSecurityException {
-        PublicKeyCallback pwcb = 
-            new PublicKeyCallback(publicKey);
-        try {
-            Callback[] callbacks = new Callback[]{pwcb};
-            cb.handle(callbacks);
-            if (!pwcb.isVerified()) {
-                throw new WSSecurityException(
-                    WSSecurityException.FAILED_AUTHENTICATION, null, null, null
-                );
-            }
-        } catch (Exception e) {
-            throw new WSSecurityException(
-                WSSecurityException.FAILED_AUTHENTICATION, null, null, e
-            );
-        }
-        return new PublicKeyPrincipal(publicKey);
-    }
-    
 
     /**
      * Verify the WS-Security signature.

Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/TimestampProcessor.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/TimestampProcessor.java?rev=1062763&r1=1062762&r2=1062763&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/TimestampProcessor.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/TimestampProcessor.java Mon Jan 24 13:15:50 2011
@@ -28,6 +28,9 @@ import org.apache.ws.security.WSSecurity
 import org.apache.ws.security.WSSecurityException;
 import org.apache.ws.security.components.crypto.Crypto;
 import org.apache.ws.security.message.token.Timestamp;
+import org.apache.ws.security.validate.Credential;
+import org.apache.ws.security.validate.TimestampValidator;
+import org.apache.ws.security.validate.Validator;
 import org.w3c.dom.Element;
 
 import java.util.List;
@@ -35,6 +38,7 @@ import javax.security.auth.callback.Call
 
 public class TimestampProcessor implements Processor {
     private static Log log = LogFactory.getLog(TimestampProcessor.class.getName());
+    private Validator validator = new TimestampValidator();
 
     public List<WSSecurityEngineResult> handleToken(
         Element elem, 
@@ -51,7 +55,11 @@ public class TimestampProcessor implemen
         // Decode Timestamp, add the found time (created/expiry) to result
         //
         Timestamp timestamp = new Timestamp(elem);
-        handleTimestamp(timestamp, wsc);
+        Credential credential = new Credential();
+        credential.setTimestamp(timestamp);
+        validator.setWSSConfig(wsc);
+        validator.validate(credential);
+        
         WSSecurityEngineResult result = 
             new WSSecurityEngineResult(WSConstants.TS, timestamp);
         result.put(WSSecurityEngineResult.TAG_ID, timestamp.getID());
@@ -60,23 +68,4 @@ public class TimestampProcessor implemen
         return java.util.Collections.singletonList(result);
     }
 
-    private void handleTimestamp(
-        Timestamp timestamp, 
-        WSSConfig wssConfig
-    ) throws WSSecurityException {
-        if (log.isDebugEnabled()) {
-            log.debug("Preparing to verify the timestamp");
-        }
-
-        // Validate whether the security semantics have expired
-        if ((wssConfig.isTimeStampStrict() && timestamp.isExpired()) 
-            || !timestamp.verifyCreated(wssConfig.getTimeStampTTL())) {
-            throw new WSSecurityException(
-                WSSecurityException.MESSAGE_EXPIRED,
-                "invalidTimestamp",
-                new Object[] {"The security semantics of the message have expired"}
-            );
-        }
-    }
-    
 }

Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/UsernameTokenProcessor.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/UsernameTokenProcessor.java?rev=1062763&r1=1062762&r2=1062763&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/UsernameTokenProcessor.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/UsernameTokenProcessor.java Mon Jan 24 13:15:50 2011
@@ -23,24 +23,24 @@ import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.ws.security.WSConstants;
 import org.apache.ws.security.WSDocInfo;
-import org.apache.ws.security.WSPasswordCallback;
 import org.apache.ws.security.WSSConfig;
 import org.apache.ws.security.WSSecurityEngineResult;
 import org.apache.ws.security.WSSecurityException;
 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.apache.ws.security.validate.Credential;
+import org.apache.ws.security.validate.UsernameTokenValidator;
+import org.apache.ws.security.validate.Validator;
 import org.w3c.dom.Element;
 
-import javax.security.auth.callback.Callback;
 import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.UnsupportedCallbackException;
-import java.io.IOException;
 import java.util.List;
 
 public class UsernameTokenProcessor implements Processor {
     private static Log log = LogFactory.getLog(UsernameTokenProcessor.class.getName());
+    
+    private Validator validator = new UsernameTokenValidator();
 
     public List<WSSecurityEngineResult> handleToken(
         Element elem, Crypto crypto, Crypto decCrypto, CallbackHandler cb, 
@@ -49,8 +49,10 @@ public class UsernameTokenProcessor impl
         if (log.isDebugEnabled()) {
             log.debug("Found UsernameToken list element");
         }
+        validator.setCallbackHandler(cb);
+        validator.setWSSConfig(wsc);
         
-        UsernameToken token = handleUsernameToken(elem, cb, wsc);
+        UsernameToken token = handleUsernameToken(elem, wsc);
         
         WSUsernameTokenPrincipal principal = 
             new WSUsernameTokenPrincipal(token.getName(), token.isHashed());
@@ -80,7 +82,6 @@ public class UsernameTokenProcessor impl
      * <code>USERNAME_TOKEN_UNKNOWN</code>.
      *
      * @param token the DOM element that contains the UsernameToken
-     * @param cb    the reference to the callback object
      * @param wssConfig The WSSConfig object from which to obtain configuration
      * @return UsernameToken the UsernameToken object that was parsed
      * @throws WSSecurityException
@@ -88,127 +89,22 @@ public class UsernameTokenProcessor impl
     public UsernameToken 
     handleUsernameToken(
         Element token, 
-        CallbackHandler cb,
         WSSConfig wssConfig
     ) throws WSSecurityException {
-        if (cb == null) {
-            throw new WSSecurityException(WSSecurityException.FAILURE, "noCallback");
-        }
-        boolean handleCustomPasswordTypes = false;
         boolean allowNamespaceQualifiedPasswordTypes = false;
-        boolean passwordsAreEncoded = false;
-        
         if (wssConfig != null) {
-            handleCustomPasswordTypes = wssConfig.getHandleCustomPasswordTypes();
             allowNamespaceQualifiedPasswordTypes = 
                 wssConfig.getAllowNamespaceQualifiedPasswordTypes();
-            passwordsAreEncoded = wssConfig.getPasswordsAreEncoded();
         }
         
         //
-        // Parse the UsernameToken element
+        // Parse and validate the UsernameToken element
         //
         UsernameToken ut = new UsernameToken(token, allowNamespaceQualifiedPasswordTypes);
-        ut.setPasswordsAreEncoded(passwordsAreEncoded);
-        String user = ut.getName();
-        String password = ut.getPassword();
-        String nonce = ut.getNonce();
-        String createdTime = ut.getCreated();
-        String pwType = ut.getPasswordType();
-        if (log.isDebugEnabled()) {
-            log.debug("UsernameToken user " + user);
-            log.debug("UsernameToken password type " + pwType);
-        }
+        Credential credential = new Credential();
+        credential.setUsernametoken(ut);
+        validator.validate(credential);
         
-        if (wssConfig != null) {
-            String requiredPasswordType = wssConfig.getRequiredPasswordType();
-            if (requiredPasswordType != null && !requiredPasswordType.equals(pwType)) {
-                if (log.isDebugEnabled()) {
-                    log.debug("Authentication failed as the received password type does not " 
-                        + "match the required password type of: " + requiredPasswordType);
-                }
-                throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
-            }
-        }
-        //
-        // If the UsernameToken is hashed or plaintext, then retrieve the password from the
-        // callback handler and compare directly. If the UsernameToken is of some unknown type,
-        // then delegate authentication to the callback handler
-        //
-        if (ut.isHashed() || WSConstants.PASSWORD_TEXT.equals(pwType) 
-            || (password != null && (pwType == null || "".equals(pwType.trim())))) {
-            WSPasswordCallback pwCb = 
-                new WSPasswordCallback(user, null, pwType, WSPasswordCallback.USERNAME_TOKEN);
-            try {
-                cb.handle(new Callback[]{pwCb});
-            } catch (IOException e) {
-                if (log.isDebugEnabled()) {
-                    log.debug(e);
-                }
-                throw new WSSecurityException(
-                    WSSecurityException.FAILED_AUTHENTICATION, null, null, e
-                );
-            } catch (UnsupportedCallbackException e) {
-                if (log.isDebugEnabled()) {
-                    log.debug(e);
-                }
-                throw new WSSecurityException(
-                    WSSecurityException.FAILED_AUTHENTICATION, null, null, e
-                );
-            }
-            String origPassword = pwCb.getPassword();
-            if (origPassword == null) {
-                if (log.isDebugEnabled()) {
-                    log.debug("Callback supplied no password for: " + user);
-                }
-                throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
-            }
-            if (ut.isHashed()) {
-                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);
-                }
-            } else {
-                if (!origPassword.equals(password)) {
-                    throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
-                }
-            }
-            ut.setRawPassword(origPassword);
-        } else {
-            if (pwType != null && !handleCustomPasswordTypes) {
-                if (log.isDebugEnabled()) {
-                    log.debug("Authentication failed as handleCustomUsernameTokenTypes is false");
-                }
-                throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
-            }
-            WSPasswordCallback pwCb = new WSPasswordCallback(user, password,
-                    pwType, WSPasswordCallback.USERNAME_TOKEN_UNKNOWN);
-            try {
-                cb.handle(new Callback[]{pwCb});
-            } catch (IOException e) {
-                if (log.isDebugEnabled()) {
-                    log.debug(e);
-                }
-                throw new WSSecurityException(
-                    WSSecurityException.FAILED_AUTHENTICATION, null, null, e
-                );
-            } catch (UnsupportedCallbackException e) {
-                if (log.isDebugEnabled()) {
-                    log.debug(e);
-                }
-                throw new WSSecurityException(
-                    WSSecurityException.FAILED_AUTHENTICATION, null, null, e
-                );
-            }
-            String origPassword = pwCb.getPassword();
-            ut.setRawPassword(origPassword);
-        }
-
         return ut;
     }
 

Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/saml/ext/AssertionWrapper.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/saml/ext/AssertionWrapper.java?rev=1062763&r1=1062762&r2=1062763&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/saml/ext/AssertionWrapper.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/saml/ext/AssertionWrapper.java Mon Jan 24 13:15:50 2011
@@ -510,9 +510,10 @@ public class AssertionWrapper {
     /**
      * Verify the signature of this assertion
      *
+     * @return the SAMLKeyInfo structure containing the credentials used to verify the signature
      * @throws ValidationException
      */
-    public void verify(Crypto crypto) throws WSSecurityException {
+    public SAMLKeyInfo verify(Crypto crypto) throws WSSecurityException {
         Signature sig = null;
         if (saml2 != null && saml2.getSignature() != null) {
             sig = saml2.getSignature();
@@ -553,9 +554,11 @@ public class AssertionWrapper {
             } catch (ValidationException ex) {
                 throw new WSSecurityException("SAML signature validation failed", ex);
             }
+            return samlKeyInfo;
         } else {
             log.debug("AssertionWrapper: no signature to validate");
         }
+        return null;
     }
     
 

Added: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/Credential.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/Credential.java?rev=1062763&view=auto
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/Credential.java (added)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/Credential.java Mon Jan 24 13:15:50 2011
@@ -0,0 +1,70 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ws.security.validate;
+
+import java.security.PublicKey;
+import java.security.cert.X509Certificate;
+
+import org.apache.ws.security.message.token.Timestamp;
+import org.apache.ws.security.message.token.UsernameToken;
+
+/**
+ * This interface describes an abstract concept of a Credential to be validated.
+ */
+public class Credential {
+    
+    private PublicKey publicKey;
+    private X509Certificate[] certs;
+    private Timestamp timestamp;
+    private UsernameToken usernametoken;
+    
+    public void setPublicKey(PublicKey publicKey) {
+        this.publicKey = publicKey;
+    }
+    
+    public PublicKey getPublicKey() {
+        return publicKey;
+    }
+    
+    public void setCertificates(X509Certificate[] certs) {
+        this.certs = certs;
+    }
+    
+    public X509Certificate[] getCertificates() {
+        return certs;
+    }
+    
+    public void setTimestamp(Timestamp timestamp) {
+        this.timestamp = timestamp;
+    }
+    
+    public Timestamp getTimestamp() {
+        return timestamp;
+    }
+    
+    public void setUsernametoken(UsernameToken usernametoken) {
+        this.usernametoken = usernametoken;
+    }
+    
+    public UsernameToken getUsernametoken() {
+        return usernametoken;
+    }
+    
+}

Added: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/SignatureTrustValidator.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/SignatureTrustValidator.java?rev=1062763&view=auto
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/SignatureTrustValidator.java (added)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/SignatureTrustValidator.java Mon Jan 24 13:15:50 2011
@@ -0,0 +1,264 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ws.security.validate;
+
+import java.math.BigInteger;
+import java.security.PublicKey;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Certificate;
+
+import javax.security.auth.callback.CallbackHandler;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ws.security.WSSConfig;
+import org.apache.ws.security.WSSecurityException;
+import org.apache.ws.security.components.crypto.Crypto;
+
+/**
+ * This interface describes a pluggable way of validating credentials that have been extracted
+ * by the processors.
+ */
+public class SignatureTrustValidator implements Validator {
+    
+    private static Log LOG = LogFactory.getLog(SignatureTrustValidator.class.getName());
+    private Crypto crypto;
+    
+    public void validate(Credential credential) throws WSSecurityException {
+        if (credential == null) {
+            throw new WSSecurityException("Credential cannot be null");
+        }
+        X509Certificate[] certs = credential.getCertificates();
+        PublicKey publicKey = credential.getPublicKey();
+        if (crypto == null) {
+            throw new WSSecurityException("Crypto instance cannot be null");
+        }
+        
+        if (certs != null && certs.length > 0) {
+            validateCertificates(certs);
+            boolean trust = false;
+            if (certs.length == 1) {
+                trust = verifyTrustInCert(certs);
+            } else {
+                trust = verifyTrustInCerts(certs);
+            }
+            if (trust) {
+                return;
+            }
+        }
+        if (publicKey != null) {
+            boolean trust = validatePublicKey(publicKey);
+            if (trust) {
+                return;
+            }
+        }
+        throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION, null);
+    }
+    
+    public void setWSSConfig(WSSConfig wssConfig) {
+        //
+    }
+    
+    public void setCrypto(Crypto crypto) {
+        this.crypto = crypto;
+    }
+    
+    public void setCallbackHandler(CallbackHandler callbackHandler) {
+        //
+    }
+    
+    /**
+     * Validate the certificates by checking the validity of each cert
+     * @throws WSSecurityException
+     */
+    private void validateCertificates(X509Certificate[] certificates) throws WSSecurityException {
+        try {
+            for (int i = 0; i < certificates.length; i++) {
+                certificates[i].checkValidity();
+            }
+        } catch (CertificateExpiredException e) {
+            throw new WSSecurityException(
+                WSSecurityException.FAILED_CHECK, "invalidCert", null, e
+            );
+        } catch (CertificateNotYetValidException e) {
+            throw new WSSecurityException(
+                WSSecurityException.FAILED_CHECK, "invalidCert", null, e
+            );
+        }
+    }
+    
+    /**
+     * Evaluate whether a given certificate should be trusted.
+     * 
+     * Policy used in this implementation:
+     * 1. Search the keystore for the transmitted certificate
+     * 2. Search the keystore for a connection to the transmitted certificate
+     * (that is, search for certificate(s) of the issuer of the transmitted certificate
+     * 3. Verify the trust path for those certificates found because the search for the issuer 
+     * might be fooled by a phony DN (String!)
+     *
+     * @param cert the certificate that should be validated against the keystore
+     * @return true if the certificate is trusted, false if not
+     * @throws WSSecurityException
+     */
+    private boolean verifyTrustInCert(X509Certificate[] certificates) throws WSSecurityException {
+        X509Certificate cert = certificates[0];
+        
+        String subjectString = cert.getSubjectX500Principal().getName();
+        String issuerString = cert.getIssuerX500Principal().getName();
+        BigInteger issuerSerial = cert.getSerialNumber();
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Transmitted certificate has subject " + subjectString);
+            LOG.debug(
+                "Transmitted certificate has issuer " + issuerString + " (serial " 
+                + issuerSerial + ")"
+            );
+        }
+
+        //
+        // FIRST step - Search the keystore for the transmitted certificate
+        //
+        if (crypto.isCertificateInKeyStore(cert)) {
+            return true;
+        }
+
+        //
+        // SECOND step - Search for the issuer of the transmitted certificate in the 
+        // keystore or the truststore
+        //
+        String[] aliases = crypto.getAliasesForDN(issuerString);
+
+        // If the alias has not been found, the issuer is not in the keystore/truststore
+        // As a direct result, do not trust the transmitted certificate
+        if (aliases == null || aliases.length < 1) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug(
+                    "No aliases found in keystore for issuer " + issuerString 
+                    + " of certificate for " + subjectString
+                );
+            }
+            return false;
+        }
+
+        //
+        // THIRD step
+        // Check the certificate trust path for every alias of the issuer found in the 
+        // keystore/truststore
+        //
+        for (int i = 0; i < aliases.length; i++) {
+            String alias = aliases[i];
+
+            if (LOG.isDebugEnabled()) {
+                LOG.debug(
+                    "Preparing to validate certificate path with alias " + alias 
+                    + " for issuer " + issuerString
+                );
+            }
+
+            // Retrieve the certificate(s) for the alias from the keystore/truststore
+            X509Certificate[] certs = crypto.getCertificates(alias);
+
+            // If no certificates have been found, there has to be an error:
+            // The keystore/truststore can find an alias but no certificate(s)
+            if (certs == null || certs.length < 1) {
+                throw new WSSecurityException(
+                    "Could not get certificates for alias " + alias
+                );
+            }
+
+            //
+            // Form a certificate chain from the transmitted certificate
+            // and the certificate(s) of the issuer from the keystore/truststore
+            //
+            X509Certificate[] x509certs = new X509Certificate[certs.length + 1];
+            x509certs[0] = cert;
+            for (int j = 0; j < certs.length; j++) {
+                x509certs[j + 1] = certs[j];
+            }
+
+            //
+            // Use the validation method from the crypto to check whether the subjects' 
+            // certificate was really signed by the issuer stated in the certificate
+            //
+            if (crypto.validateCertPath(x509certs)) {
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug(
+                        "Certificate path has been verified for certificate with subject " 
+                        + subjectString
+                    );
+                }
+                return true;
+            }
+        }
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(
+                "Certificate path could not be verified for certificate with subject " 
+                + subjectString
+            );
+        }
+        return false;
+    }
+    
+    /**
+     * Evaluate whether the given certificate chain should be trusted.
+     * 
+     * @param certificates the certificate chain that should be validated against the keystore
+     * @return true if the certificate chain is trusted, false if not
+     * @throws WSSecurityException
+     */
+    private boolean verifyTrustInCerts(X509Certificate[] certificates) throws WSSecurityException {
+        String subjectString = certificates[0].getSubjectX500Principal().getName();
+        //
+        // Use the validation method from the crypto to check whether the subjects' 
+        // certificate was really signed by the issuer stated in the certificate
+        //
+        if (certificates != null && certificates.length > 1
+            && crypto.validateCertPath(certificates)) {
+            if (LOG.isDebugEnabled()) {
+                LOG.debug(
+                    "Certificate path has been verified for certificate with subject " 
+                    + subjectString
+                );
+            }
+            return true;
+        }
+        
+        if (LOG.isDebugEnabled()) {
+            LOG.debug(
+                "Certificate path could not be verified for certificate with subject " 
+                + subjectString
+            );
+        }
+            
+        return false;
+    }
+    
+    /**
+     * Validate a public key
+     * @throws WSSecurityException
+     */
+    private boolean validatePublicKey(PublicKey publicKey) throws WSSecurityException {
+        return crypto.verifyTrust(publicKey);
+    }
+    
+}

Added: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/TimestampValidator.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/TimestampValidator.java?rev=1062763&view=auto
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/TimestampValidator.java (added)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/TimestampValidator.java Mon Jan 24 13:15:50 2011
@@ -0,0 +1,72 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ws.security.validate;
+
+import javax.security.auth.callback.CallbackHandler;
+
+import org.apache.ws.security.WSSConfig;
+import org.apache.ws.security.WSSecurityException;
+import org.apache.ws.security.components.crypto.Crypto;
+import org.apache.ws.security.message.token.Timestamp;
+
+/**
+ * This interface describes a pluggable way of validating credentials that have been extracted
+ * by the processors.
+ */
+public class TimestampValidator implements Validator {
+    
+    private WSSConfig wssConfig;
+    
+    public void validate(Credential credential) throws WSSecurityException {
+        if (credential == null) {
+            throw new WSSecurityException("Credential cannot be null");
+        }
+        Timestamp timeStamp = credential.getTimestamp();
+        if (timeStamp == null) {
+            throw new WSSecurityException(WSSecurityException.MESSAGE_EXPIRED, "invalidTimestamp");
+        }
+        if (wssConfig == null) {
+            throw new WSSecurityException("WSSConfig cannot be null");
+        }
+        
+        // Validate whether the security semantics have expired
+        if ((wssConfig.isTimeStampStrict() && timeStamp.isExpired()) 
+            || !timeStamp.verifyCreated(wssConfig.getTimeStampTTL())) {
+            throw new WSSecurityException(
+                WSSecurityException.MESSAGE_EXPIRED,
+                "invalidTimestamp",
+                new Object[] {"The security semantics of the message have expired"}
+            );
+        }
+    }
+    
+    public void setWSSConfig(WSSConfig wssConfig) {
+        this.wssConfig = wssConfig;
+    }
+    
+    public void setCrypto(Crypto crypto) {
+        //
+    }
+    
+    public void setCallbackHandler(CallbackHandler callbackHandler) {
+        //
+    }
+   
+}

Added: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/UsernameTokenValidator.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/UsernameTokenValidator.java?rev=1062763&view=auto
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/UsernameTokenValidator.java (added)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/UsernameTokenValidator.java Mon Jan 24 13:15:50 2011
@@ -0,0 +1,182 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ws.security.validate;
+
+import java.io.IOException;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.ws.security.WSConstants;
+import org.apache.ws.security.WSPasswordCallback;
+import org.apache.ws.security.WSSConfig;
+import org.apache.ws.security.WSSecurityException;
+import org.apache.ws.security.components.crypto.Crypto;
+import org.apache.ws.security.message.token.UsernameToken;
+import org.apache.ws.security.util.Base64;
+
+/**
+ * This interface describes a pluggable way of validating credentials that have been extracted
+ * by the processors.
+ */
+public class UsernameTokenValidator implements Validator {
+    
+    private static Log log = LogFactory.getLog(UsernameTokenValidator.class.getName());
+    
+    private WSSConfig wssConfig;
+    private CallbackHandler callbackHandler;
+    
+    public void validate(Credential credential) throws WSSecurityException {
+        if (credential == null) {
+            throw new WSSecurityException("Credential cannot be null");
+        }
+        if (wssConfig == null) {
+            throw new WSSecurityException("WSSConfig cannot be null");
+        }
+        if (callbackHandler == null) {
+            throw new WSSecurityException(WSSecurityException.FAILURE, "noCallback");
+        }
+        
+        boolean handleCustomPasswordTypes = wssConfig.getHandleCustomPasswordTypes();
+        boolean passwordsAreEncoded = wssConfig.getPasswordsAreEncoded();
+        
+        UsernameToken usernameToken = credential.getUsernametoken();
+        if (usernameToken == null) {
+            throw new WSSecurityException("Username Token cannot be null");
+        }
+        usernameToken.setPasswordsAreEncoded(passwordsAreEncoded);
+        
+        String user = usernameToken.getName();
+        String password = usernameToken.getPassword();
+        String nonce = usernameToken.getNonce();
+        String createdTime = usernameToken.getCreated();
+        String pwType = usernameToken.getPasswordType();
+        if (log.isDebugEnabled()) {
+            log.debug("UsernameToken user " + user);
+            log.debug("UsernameToken password type " + pwType);
+        }
+        
+        String requiredPasswordType = wssConfig.getRequiredPasswordType();
+        if (requiredPasswordType != null && !requiredPasswordType.equals(pwType)) {
+            if (log.isDebugEnabled()) {
+                log.debug("Authentication failed as the received password type does not " 
+                    + "match the required password type of: " + requiredPasswordType);
+            }
+            throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
+        }
+        
+        
+        //
+        // If the UsernameToken is hashed or plaintext, then retrieve the password from the
+        // callback handler and compare directly. If the UsernameToken is of some unknown type,
+        // then delegate authentication to the callback handler
+        //
+        if (usernameToken.isHashed() || WSConstants.PASSWORD_TEXT.equals(pwType) 
+            || (password != null && (pwType == null || "".equals(pwType.trim())))) {
+            WSPasswordCallback pwCb = 
+                new WSPasswordCallback(user, null, pwType, WSPasswordCallback.USERNAME_TOKEN);
+            try {
+                callbackHandler.handle(new Callback[]{pwCb});
+            } catch (IOException e) {
+                if (log.isDebugEnabled()) {
+                    log.debug(e);
+                }
+                throw new WSSecurityException(
+                    WSSecurityException.FAILED_AUTHENTICATION, null, null, e
+                );
+            } catch (UnsupportedCallbackException e) {
+                if (log.isDebugEnabled()) {
+                    log.debug(e);
+                }
+                throw new WSSecurityException(
+                    WSSecurityException.FAILED_AUTHENTICATION, null, null, e
+                );
+            }
+            String origPassword = pwCb.getPassword();
+            if (origPassword == null) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Callback supplied no password for: " + user);
+                }
+                throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
+            }
+            if (usernameToken.isHashed()) {
+                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);
+                }
+            } else {
+                if (!origPassword.equals(password)) {
+                    throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
+                }
+            }
+            usernameToken.setRawPassword(origPassword);
+        } else {
+            if (pwType != null && !handleCustomPasswordTypes) {
+                if (log.isDebugEnabled()) {
+                    log.debug("Authentication failed as handleCustomUsernameTokenTypes is false");
+                }
+                throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);
+            }
+            WSPasswordCallback pwCb = new WSPasswordCallback(user, password,
+                    pwType, WSPasswordCallback.USERNAME_TOKEN_UNKNOWN);
+            try {
+                callbackHandler.handle(new Callback[]{pwCb});
+            } catch (IOException e) {
+                if (log.isDebugEnabled()) {
+                    log.debug(e);
+                }
+                throw new WSSecurityException(
+                    WSSecurityException.FAILED_AUTHENTICATION, null, null, e
+                );
+            } catch (UnsupportedCallbackException e) {
+                if (log.isDebugEnabled()) {
+                    log.debug(e);
+                }
+                throw new WSSecurityException(
+                    WSSecurityException.FAILED_AUTHENTICATION, null, null, e
+                );
+            }
+            String origPassword = pwCb.getPassword();
+            usernameToken.setRawPassword(origPassword);
+        }
+        
+    }
+    
+    public void setWSSConfig(WSSConfig wssConfig) {
+        this.wssConfig = wssConfig;
+    }
+    
+    public void setCrypto(Crypto crypto) {
+        //
+    }
+    
+    public void setCallbackHandler(CallbackHandler callbackHandler) {
+        this.callbackHandler = callbackHandler;
+    }
+   
+}

Added: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/Validator.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/Validator.java?rev=1062763&view=auto
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/Validator.java (added)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/validate/Validator.java Mon Jan 24 13:15:50 2011
@@ -0,0 +1,42 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.ws.security.validate;
+
+import javax.security.auth.callback.CallbackHandler;
+
+import org.apache.ws.security.WSSConfig;
+import org.apache.ws.security.WSSecurityException;
+import org.apache.ws.security.components.crypto.Crypto;
+
+/**
+ * This interface describes a pluggable way of validating credentials that have been extracted
+ * by the processors.
+ */
+public interface Validator {
+    
+    public void validate(Credential credential) throws WSSecurityException;
+    
+    public void setCrypto(Crypto crypto);
+    
+    public void setCallbackHandler(CallbackHandler callbackHandler);
+    
+    public void setWSSConfig(WSSConfig wssConfig);
+    
+}

Modified: webservices/wss4j/trunk/src/test/java/org/apache/ws/security/common/KeystoreCallbackHandler.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/test/java/org/apache/ws/security/common/KeystoreCallbackHandler.java?rev=1062763&r1=1062762&r2=1062763&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/test/java/org/apache/ws/security/common/KeystoreCallbackHandler.java (original)
+++ webservices/wss4j/trunk/src/test/java/org/apache/ws/security/common/KeystoreCallbackHandler.java Mon Jan 24 13:15:50 2011
@@ -47,15 +47,7 @@ public class KeystoreCallbackHandler imp
         for (int i = 0; i < callbacks.length; i++) {
             if (callbacks[i] instanceof WSPasswordCallback) {
                 WSPasswordCallback pc = (WSPasswordCallback) callbacks[i];
-                switch (pc.getUsage()) {
-                case WSPasswordCallback.CUSTOM_TOKEN:
-                case WSPasswordCallback.DECRYPT: {
-                    pc.setPassword(users.get(pc.getIdentifier()));
-                    break;
-                }
-                default:
-                    throw new IOException("Authentication failed");
-                }
+                pc.setPassword(users.get(pc.getIdentifier()));
             } else {
                 throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback");
             }

Modified: webservices/wss4j/trunk/src/test/java/org/apache/ws/security/message/SignatureKeyValueTest.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/test/java/org/apache/ws/security/message/SignatureKeyValueTest.java?rev=1062763&r1=1062762&r2=1062763&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/test/java/org/apache/ws/security/message/SignatureKeyValueTest.java (original)
+++ webservices/wss4j/trunk/src/test/java/org/apache/ws/security/message/SignatureKeyValueTest.java Mon Jan 24 13:15:50 2011
@@ -25,7 +25,6 @@ import org.apache.ws.security.PublicKeyP
 import org.apache.ws.security.WSConstants;
 import org.apache.ws.security.WSSecurityEngine;
 import org.apache.ws.security.WSSecurityEngineResult;
-import org.apache.ws.security.common.PublicKeyCallbackHandler;
 import org.apache.ws.security.common.SOAPUtil;
 import org.apache.ws.security.components.crypto.Crypto;
 import org.apache.ws.security.components.crypto.CryptoFactory;
@@ -43,11 +42,6 @@ public class SignatureKeyValueTest exten
     private static final Log LOG = LogFactory.getLog(SignatureKeyValueTest.class);
     private WSSecurityEngine secEngine = new WSSecurityEngine();
     private Crypto crypto = CryptoFactory.getInstance("wss40.properties");
-    private PublicKeyCallbackHandler callbackHandler = new PublicKeyCallbackHandler();
-
-    public SignatureKeyValueTest() {
-        callbackHandler.setKeyStore(crypto.getKeyStore());
-    }
 
     /**
      * Successful RSAKeyValue test.
@@ -158,7 +152,7 @@ public class SignatureKeyValueTest exten
      * @throws java.lang.Exception Thrown when there is a problem in verification
      */
     private List<WSSecurityEngineResult> verify(Document doc) throws Exception {
-        return secEngine.processSecurityHeader(doc, null, callbackHandler, null);
+        return secEngine.processSecurityHeader(doc, null, null, crypto);
     }
     
 }

Modified: webservices/wss4j/trunk/src/test/java/org/apache/ws/security/saml/SamlTokenHOKTest.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/test/java/org/apache/ws/security/saml/SamlTokenHOKTest.java?rev=1062763&r1=1062762&r2=1062763&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/test/java/org/apache/ws/security/saml/SamlTokenHOKTest.java (original)
+++ webservices/wss4j/trunk/src/test/java/org/apache/ws/security/saml/SamlTokenHOKTest.java Mon Jan 24 13:15:50 2011
@@ -260,7 +260,7 @@ public class SamlTokenHOKTest extends or
      */
     private List<WSSecurityEngineResult> verify(Document doc) throws Exception {
         List<WSSecurityEngineResult> results = 
-            secEngine.processSecurityHeader(doc, null, null, null);
+            secEngine.processSecurityHeader(doc, null, null, crypto);
         String outputString = 
             org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(doc);
         assertTrue(outputString.indexOf("counter_port_type") > 0 ? true : false);

Modified: webservices/wss4j/trunk/src/test/java/org/apache/ws/security/saml/SignedSamlTokenHOKTest.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/test/java/org/apache/ws/security/saml/SignedSamlTokenHOKTest.java?rev=1062763&r1=1062762&r2=1062763&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/test/java/org/apache/ws/security/saml/SignedSamlTokenHOKTest.java (original)
+++ webservices/wss4j/trunk/src/test/java/org/apache/ws/security/saml/SignedSamlTokenHOKTest.java Mon Jan 24 13:15:50 2011
@@ -145,61 +145,6 @@ public class SignedSamlTokenHOKTest exte
     }
     
     /**
-     * Test that creates, sends and processes a signed SAML 1.1 authentication assertion, where
-     * the configuration is loaded from a properties file
-     */
-    @org.junit.Test
-    @SuppressWarnings("unchecked")
-    public void testSAML1AuthnAssertionFromProperties() throws Exception {
-        SAMLIssuer saml = SAMLIssuerFactory.getInstance("saml_hok.properties");
-        AssertionWrapper assertion = saml.newAssertion();
-
-        WSSecSignatureSAML wsSign = new WSSecSignatureSAML();
-        wsSign.setUserInfo("wss40", "security");
-        wsSign.setDigestAlgo("http://www.w3.org/2001/04/xmlenc#sha256");
-        wsSign.setSignatureAlgorithm("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256");
-        wsSign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
-
-        Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
-        WSSecHeader secHeader = new WSSecHeader();
-        secHeader.insertSecurityHeader(doc);
-
-        Document signedDoc = 
-            wsSign.build(doc, userCrypto, assertion, null, null, null, secHeader);
-
-        String outputString = 
-            org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
-        if (LOG.isDebugEnabled()) {
-            LOG.debug("Signed SAML 1.1 Authn Assertion (key holder):");
-            LOG.debug(outputString);
-        }
-        assertTrue(outputString.indexOf("http://www.w3.org/2001/04/xmlenc#sha256") != -1);
-        assertTrue(outputString.indexOf("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256") != -1);
-        
-        List<WSSecurityEngineResult> results = verify(signedDoc, trustCrypto);
-        
-        // Test we processed a SAML assertion
-        WSSecurityEngineResult actionResult =
-            WSSecurityUtil.fetchActionResult(results, WSConstants.ST_SIGNED);
-        AssertionWrapper receivedAssertion = 
-            (AssertionWrapper) actionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
-        assertTrue(receivedAssertion != null);
-        assert receivedAssertion.isSigned();
-        
-        // Test we processed a signature (SOAP body)
-        actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
-        assertTrue(actionResult != null);
-        assertFalse(actionResult.isEmpty());
-        final List<WSDataRef> refs =
-            (List<WSDataRef>) actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
-        assertTrue(refs.size() == 1);
-        
-        WSDataRef wsDataRef = (WSDataRef)refs.get(0);
-        String xpath = wsDataRef.getXpath();
-        assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body", xpath);
-    }
-    
-    /**
      * Test that creates, sends and processes a signed SAML 1.1 attribute assertion.
      */
     @org.junit.Test
@@ -473,7 +418,6 @@ public class SignedSamlTokenHOKTest exte
         saml.setIssuerKeyName("wss40_server");
         saml.setIssuerKeyPassword("security");
         saml.setSignAssertion(true);
-        // saml.setSamlVersion("2.0");
         saml.setCallbackHandler(callbackHandler);
         AssertionWrapper assertion = saml.newAssertion();