You are viewing a plain text version of this content. The canonical link for it is here.
Posted to axis-cvs@ws.apache.org by ru...@apache.org on 2006/10/30 11:35:34 UTC

svn commit: r469110 - in /webservices/axis2/branches/java/1_1/modules/security/src/org/apache/rampart: RampartEngine.java errors.properties handler/RampartReceiver.java

Author: ruchithf
Date: Mon Oct 30 02:35:33 2006
New Revision: 469110

URL: http://svn.apache.org/viewvc?view=rev&rev=469110
Log:
Porting trust verificattion and timestamp validation of the security procesing results into new rampart handlers

Modified:
    webservices/axis2/branches/java/1_1/modules/security/src/org/apache/rampart/RampartEngine.java
    webservices/axis2/branches/java/1_1/modules/security/src/org/apache/rampart/errors.properties
    webservices/axis2/branches/java/1_1/modules/security/src/org/apache/rampart/handler/RampartReceiver.java

Modified: webservices/axis2/branches/java/1_1/modules/security/src/org/apache/rampart/RampartEngine.java
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/java/1_1/modules/security/src/org/apache/rampart/RampartEngine.java?view=diff&rev=469110&r1=469109&r2=469110
==============================================================================
--- webservices/axis2/branches/java/1_1/modules/security/src/org/apache/rampart/RampartEngine.java (original)
+++ webservices/axis2/branches/java/1_1/modules/security/src/org/apache/rampart/RampartEngine.java Mon Oct 30 02:35:33 2006
@@ -19,19 +19,28 @@
 import org.apache.axiom.soap.SOAPEnvelope;
 import org.apache.axis2.AxisFault;
 import org.apache.axis2.context.MessageContext;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.rampart.policy.RampartPolicyData;
 import org.apache.rampart.util.Axis2Util;
 import org.apache.rampart.util.RampartUtil;
 import org.apache.ws.secpolicy.WSSPolicyException;
+import org.apache.ws.security.WSConstants;
 import org.apache.ws.security.WSSecurityEngine;
+import org.apache.ws.security.WSSecurityEngineResult;
 import org.apache.ws.security.WSSecurityException;
+import org.apache.ws.security.message.token.Timestamp;
+import org.apache.ws.security.util.WSSecurityUtil;
 
+import java.math.BigInteger;
+import java.security.cert.X509Certificate;
+import java.util.Calendar;
+import java.util.Date;
 import java.util.Vector;
 
-
 public class RampartEngine {
 
-    
+    private static Log log = LogFactory.getLog(RampartEngine.class);    
 
     public Vector process(MessageContext msgCtx) throws WSSPolicyException,
     RampartException, WSSecurityException, AxisFault {
@@ -72,11 +81,236 @@
 
         SOAPEnvelope env = Axis2Util.getSOAPEnvelopeFromDOOMDocument(rmd.getDocument());
 
-        //Convert back to llom since the inflow cannot use llom
+        //Convert back to llom since the inflow cannot use DOOM
         msgCtx.setEnvelope(env);
         Axis2Util.useDOOM(false);
 
+        this.validateResults(rmd, results);
+        
         return results;
     }
+
+
+    private void validateResults(RampartMessageData rmd, Vector results) throws RampartException {
+
+        /*
+         * Now we can check the certificate used to sign the message. In the
+         * following implementation the certificate is only trusted if either it
+         * itself or the certificate of the issuer is installed in the keystore.
+         * 
+         * Note: the method verifyTrust(X509Certificate) allows custom
+         * implementations with other validation algorithms for subclasses.
+         */
+
+        // Extract the signature action result from the action vector
+        WSSecurityEngineResult actionResult = WSSecurityUtil.fetchActionResult(
+                results, WSConstants.SIGN);
+
+        if (actionResult != null) {
+            X509Certificate returnCert = actionResult.getCertificate();
+
+            if (returnCert != null) {
+                if (!verifyTrust(returnCert, rmd)) {
+                    throw new RampartException ("trustVerificationError");
+                }
+            }
+        }
+
+        /*
+         * Perform further checks on the timestamp that was transmitted in the
+         * header. In the following implementation the timestamp is valid if it
+         * was created after (now-ttl), where ttl is set on server side, not by
+         * the client.
+         * 
+         * Note: the method verifyTimestamp(Timestamp) allows custom
+         * implementations with other validation algorithms for subclasses.
+         */
+
+        // Extract the timestamp action result from the action vector
+        actionResult = WSSecurityUtil.fetchActionResult(results, WSConstants.TS);
+
+        if (actionResult != null) {
+            Timestamp timestamp = actionResult.getTimestamp();
+
+            if (timestamp != null) {
+                if (!verifyTimestamp(timestamp, rmd.getTimeToLive())) {
+                    throw new RampartException("cannotValidateTimestamp");
+                }
+            }
+        }
+
+    }
+
     
+    private boolean verifyTimestamp(Timestamp timestamp, int timeToLive) throws RampartException {
+
+        // Calculate the time that is allowed for the message to travel
+        Calendar validCreation = Calendar.getInstance();
+        long currentTime = validCreation.getTime().getTime();
+        currentTime -= timeToLive * 1000;
+        validCreation.setTime(new Date(currentTime));
+
+        // Validate the time it took the message to travel
+        // if (timestamp.getCreated().before(validCreation) ||
+        // !timestamp.getCreated().equals(validCreation)) {
+        Calendar cre = timestamp.getCreated();
+        if (cre != null && !cre.after(validCreation)) {
+            return false;
+        }
+
+        return true;
+    }
+    
+    /**
+     * Evaluate whether a given certificate should be trusted.
+     * Hook to allow subclasses to implement custom validation methods however they see fit.
+     * <p/>
+     * 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 (AxisFault is thrown for exceptions during CertPathValidation)
+     * @throws WSSecurityException
+     */
+    protected boolean verifyTrust(X509Certificate cert, RampartMessageData rmd) throws RampartException {
+
+        // If no certificate was transmitted, do not trust the signature
+        if (cert == null) {
+            return false;
+        }
+
+        String[] aliases = null;
+        String alias = null;
+        X509Certificate[] certs;
+
+        String subjectString = cert.getSubjectDN().getName();
+        String issuerString = cert.getIssuerDN().getName();
+        BigInteger issuerSerial = cert.getSerialNumber();
+        
+        boolean doDebug = log.isDebugEnabled();
+
+        if (doDebug) {
+            log.debug("WSHandler: Transmitted certificate has subject " + 
+                    subjectString);
+            log.debug("WSHandler: Transmitted certificate has issuer " + 
+                    issuerString + " (serial " + issuerSerial + ")");
+        }
+
+        // FIRST step
+        // Search the keystore for the transmitted certificate
+
+        // Search the keystore for the alias of the transmitted certificate
+        try {
+            alias = RampartUtil.getSignatureCrypto(
+                    rmd.getPolicyData().getRampartConfig(),
+                    rmd.getCustomClassLoader()).getAliasForX509Cert(
+                    issuerString, issuerSerial);
+        } catch (WSSecurityException ex) {
+            throw new RampartException("cannotFindAliasForCert", new String[]{subjectString}, ex);
+        }
+
+        if (alias != null) {
+            // Retrieve the certificate for the alias from the keystore
+            try {
+                certs = RampartUtil.getSignatureCrypto(
+                        rmd.getPolicyData().getRampartConfig(),
+                        rmd.getCustomClassLoader()).getCertificates(alias);
+            } catch (WSSecurityException ex) {
+                throw new RampartException("noCertForAlias", new String[] {alias}, ex);
+            }
+
+            // If certificates have been found, the certificates must be compared
+            // to ensure againgst phony DNs (compare encoded form including signature)
+            if (certs != null && certs.length > 0 && cert.equals(certs[0])) {
+                if (doDebug) {
+                    log.debug("Direct trust for certificate with " + subjectString);
+                }
+                return true;
+            }
+        } else {
+            if (doDebug) {
+                log.debug("No alias found for subject from issuer with " + issuerString + " (serial " + issuerSerial + ")");
+            }
+        }
+
+        // SECOND step
+        // Search for the issuer of the transmitted certificate in the keystore
+
+        // Search the keystore for the alias of the transmitted certificates issuer
+        try {
+            aliases = RampartUtil.getSignatureCrypto(
+                    rmd.getPolicyData().getRampartConfig(),
+                    rmd.getCustomClassLoader()).getAliasesForDN(issuerString);
+        } catch (WSSecurityException ex) {
+            throw new RampartException("cannotFindAliasForCert", new String[]{issuerString}, ex);
+        }
+
+        // If the alias has not been found, the issuer is not in the keystore
+        // As a direct result, do not trust the transmitted certificate
+        if (aliases == null || aliases.length < 1) {
+            if (doDebug) {
+                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
+        for (int i = 0; i < aliases.length; i++) {
+            alias = aliases[i];
+
+            if (doDebug) {
+                log.debug("Preparing to validate certificate path with alias " + alias + " for issuer " + issuerString);
+            }
+
+            // Retrieve the certificate(s) for the alias from the keystore
+            try {
+                certs = RampartUtil.getSignatureCrypto(
+                        rmd.getPolicyData().getRampartConfig(),
+                        rmd.getCustomClassLoader()).getCertificates(alias);
+            } catch (WSSecurityException ex) {
+                throw new RampartException("noCertForAlias", new String[] {alias}, ex);
+            }
+
+            // If no certificates have been found, there has to be an error:
+            // The keystore can find an alias but no certificate(s)
+            if (certs == null | certs.length < 1) {
+                throw new RampartException("noCertForAlias", new String[] {alias});
+            }
+
+            // Form a certificate chain from the transmitted certificate
+            // and the certificate(s) of the issuer from the keystore
+            // First, create new array
+            X509Certificate[] x509certs = new X509Certificate[certs.length + 1];
+            // Then add the first certificate ...
+            x509certs[0] = cert;
+            // ... and the other certificates
+            for (int j = 0; j < certs.length; j++) {
+                cert = certs[i];
+                x509certs[certs.length + j] = cert;
+            }
+            certs = x509certs;
+
+            // Use the validation method from the crypto to check whether the subjects certificate was really signed by the issuer stated in the certificate
+            try {
+                if (RampartUtil.getSignatureCrypto(
+                        rmd.getPolicyData().getRampartConfig(),
+                        rmd.getCustomClassLoader()).validateCertPath(certs)) {
+                    if (doDebug) {
+                        log.debug("WSHandler: Certificate path has been verified for certificate with subject " + subjectString);
+                    }
+                    return true;
+                }
+            } catch (WSSecurityException ex) {
+                throw new RampartException("certPathVerificationFailed", new String[]{subjectString}, ex);
+            }
+        }
+
+        log.debug("WSHandler: Certificate path could not be verified for certificate with subject " + subjectString);
+        return false;
+    }
+
 }

Modified: webservices/axis2/branches/java/1_1/modules/security/src/org/apache/rampart/errors.properties
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/java/1_1/modules/security/src/org/apache/rampart/errors.properties?view=diff&rev=469110&r1=469109&r2=469110
==============================================================================
--- webservices/axis2/branches/java/1_1/modules/security/src/org/apache/rampart/errors.properties (original)
+++ webservices/axis2/branches/java/1_1/modules/security/src/org/apache/rampart/errors.properties Mon Oct 30 02:35:33 2006
@@ -61,4 +61,10 @@
 noSecurityToken = Missing security token
 
 #Errors in processors
-errorProcessingUT = Error in processing UsernameToken
\ No newline at end of file
+errorProcessingUT = Error in processing UsernameToken
+
+cannotValidateTimestamp = The timestamp could not be validated
+trustVerificationError = The certificate used for the signature is not trusted
+cannotFindAliasForCert = Could not get alias for certificate with {0}
+noCertForAlias = Could not get certificates for alias  {0}
+certPathVerificationFailed = Certificate path verification failed for certificate with subject
\ No newline at end of file

Modified: webservices/axis2/branches/java/1_1/modules/security/src/org/apache/rampart/handler/RampartReceiver.java
URL: http://svn.apache.org/viewvc/webservices/axis2/branches/java/1_1/modules/security/src/org/apache/rampart/handler/RampartReceiver.java?view=diff&rev=469110&r1=469109&r2=469110
==============================================================================
--- webservices/axis2/branches/java/1_1/modules/security/src/org/apache/rampart/handler/RampartReceiver.java (original)
+++ webservices/axis2/branches/java/1_1/modules/security/src/org/apache/rampart/handler/RampartReceiver.java Mon Oct 30 02:35:33 2006
@@ -42,7 +42,7 @@
 
 
 public class RampartReceiver implements Handler {
-
+    
     protected static final WSSecurityEngine secEngine = WSSecurityEngine.getInstance();
     
     private static HandlerDescription EMPTY_HANDLER_METADATA =
@@ -127,6 +127,7 @@
 
     }
 
+    
     public HandlerDescription getHandlerDesc() {
         return this.handlerDesc;
     }



---------------------------------------------------------------------
To unsubscribe, e-mail: axis-cvs-unsubscribe@ws.apache.org
For additional commands, e-mail: axis-cvs-help@ws.apache.org