ws-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cohei...@apache.org
Subject svn commit: r1051481 - in /webservices/wss4j/trunk/src/main/java/org/apache/ws/security: processor/ str/
Date Tue, 21 Dec 2010 12:55:25 GMT
Author: coheigea
Date: Tue Dec 21 12:55:25 2010
New Revision: 1051481

URL: http://svn.apache.org/viewvc?rev=1051481&view=rev
Log:
[WSS-232] - Some cleanup of the STRParser implementations

Modified:
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/DerivedKeyTokenProcessor.java
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/EncryptedKeyProcessor.java
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/ReferenceListProcessor.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/X509Util.java
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/DerivedKeyTokenSTRParser.java
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/EncryptedKeySTRParser.java
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/STRParser.java
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/SecurityTokenRefSTRParser.java
    webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/SignatureSTRParser.java

Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/DerivedKeyTokenProcessor.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/DerivedKeyTokenProcessor.java?rev=1051481&r1=1051480&r2=1051481&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/DerivedKeyTokenProcessor.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/DerivedKeyTokenProcessor.java Tue Dec 21 12:55:25 2010
@@ -57,7 +57,7 @@ public class DerivedKeyTokenProcessor im
         if (secRefElement != null) {
             STRParser strParser = new DerivedKeyTokenSTRParser();
             strParser.parseSecurityTokenReference(
-                secRefElement, null, crypto, cb, wsDocInfo, null
+                secRefElement, crypto, cb, wsDocInfo, null
             );
             secret = strParser.getSecretKey();
         } else {

Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/EncryptedKeyProcessor.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/EncryptedKeyProcessor.java?rev=1051481&r1=1051480&r2=1051481&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/EncryptedKeyProcessor.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/EncryptedKeyProcessor.java Tue Dec 21 12:55:25 2010
@@ -184,7 +184,7 @@ public class EncryptedKeyProcessor imple
                 );
             }
             STRParser strParser = new EncryptedKeySTRParser();
-            strParser.parseSecurityTokenReference(strElement, null, crypto, cb, wsDocInfo, null);
+            strParser.parseSecurityTokenReference(strElement, crypto, cb, wsDocInfo, null);
             X509Certificate[] certs = strParser.getCertificates();
             if (certs == null || certs.length < 1 || certs[0] == null) {
                 throw new WSSecurityException(

Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/ReferenceListProcessor.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/ReferenceListProcessor.java?rev=1051481&r1=1051480&r2=1051481&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/ReferenceListProcessor.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/ReferenceListProcessor.java Tue Dec 21 12:55:25 2010
@@ -20,7 +20,9 @@
 package org.apache.ws.security.processor;
 
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import javax.crypto.SecretKey;
 import javax.security.auth.callback.CallbackHandler;
@@ -147,8 +149,10 @@ public class ReferenceListProcessor impl
             symmetricKey = X509Util.getSharedKey(keyInfoElement, symEncAlgo, cb);
         } else {
             STRParser strParser = new SecurityTokenRefSTRParser();
+            Map<String, Object> parameters = new HashMap<String, Object>();
+            parameters.put(SecurityTokenRefSTRParser.SIGNATURE_METHOD, symEncAlgo);
             strParser.parseSecurityTokenReference(
-                secRefToken, symEncAlgo, crypto, cb, wsDocInfo, null
+                secRefToken, crypto, cb, wsDocInfo, parameters
             );
             byte[] secretKey = strParser.getSecretKey();
             symmetricKey = WSSecurityUtil.prepareSecretKey(symEncAlgo, secretKey);

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=1051481&r1=1051480&r2=1051481&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 Tue Dec 21 12:55:25 2010
@@ -62,14 +62,19 @@ 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;
+import java.util.Map;
 
 public class SignatureProcessor implements Processor {
-    private static Log log = LogFactory.getLog(SignatureProcessor.class.getName());
+    private static Log LOG = LogFactory.getLog(SignatureProcessor.class.getName());
     
     private XMLSignatureFactory signatureFactory = XMLSignatureFactory.getInstance("DOM");
     
@@ -83,8 +88,8 @@ public class SignatureProcessor implemen
         WSDocInfo wsDocInfo, 
         WSSConfig wsc
     ) throws WSSecurityException {
-        if (log.isDebugEnabled()) {
-            log.debug("Found signature element");
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Found signature element");
         }
         Element keyInfoElement = 
             WSSecurityUtil.getDirectChildElement(
@@ -112,14 +117,19 @@ public class SignatureProcessor implemen
                 principal = validatePublicKey(cb, publicKey);
             } else {
                 STRParser strParser = new SignatureSTRParser();
+                Map<String, Object> parameters = new HashMap<String, Object>();
+                parameters.put(SignatureSTRParser.SIGNATURE_METHOD, signatureMethod);
+                parameters.put(
+                    SignatureSTRParser.SECRET_KEY_LENGTH, new Integer(wsc.getSecretKeyLength())
+                );
                 strParser.parseSecurityTokenReference(
-                    strElement, signatureMethod, crypto, cb, wsDocInfo, wsc
+                    strElement, crypto, cb, wsDocInfo, parameters
                 );
-                strParser.validateCredentials();
                 principal = strParser.getPrincipal();
                 certs = strParser.getCertificates();
                 publicKey = strParser.getPublicKey();
                 secretKey = strParser.getSecretKey();
+                validateCredentials(certs, crypto);
             }
         }
         
@@ -178,6 +188,214 @@ 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 {
@@ -198,7 +416,7 @@ public class SignatureProcessor implemen
                 //
                 return keyValue.getPublicKey();
             } catch (java.security.KeyException ex) {
-                log.error(ex.getMessage(), ex);
+                LOG.error(ex.getMessage(), ex);
                 throw new WSSecurityException(WSSecurityException.FAILED_CHECK, null, null, ex);
             }     
         } else {
@@ -297,8 +515,8 @@ public class SignatureProcessor implemen
         String signatureMethod,
         WSDocInfo wsDocInfo
     ) throws WSSecurityException {
-        if (log.isDebugEnabled()) {
-            log.debug("Verify XML Signature");
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Verify XML Signature");
         }
         
         //
@@ -329,11 +547,11 @@ public class SignatureProcessor implemen
                 //
                 // Log the exact signature error
                 //
-                if (log.isDebugEnabled()) {
-                    log.debug("XML Signature verification has failed");
+                if (LOG.isDebugEnabled()) {
+                    LOG.debug("XML Signature verification has failed");
                     boolean signatureValidationCheck = 
                         xmlSignature.getSignatureValue().validate(context);
-                    log.debug("Signature Validation check: " + signatureValidationCheck);
+                    LOG.debug("Signature Validation check: " + signatureValidationCheck);
                     java.util.Iterator<?> referenceIterator = 
                         xmlSignature.getSignedInfo().getReferences().iterator();
                     while (referenceIterator.hasNext()) {
@@ -343,7 +561,7 @@ public class SignatureProcessor implemen
                         if (id == null) {
                             id = reference.getURI();
                         }
-                        log.debug("Reference " + id + " check: " + referenceValidationCheck);
+                        LOG.debug("Reference " + id + " check: " + referenceValidationCheck);
                     }
                 }
                 

Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/X509Util.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/X509Util.java?rev=1051481&r1=1051480&r2=1051481&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/X509Util.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/processor/X509Util.java Tue Dec 21 12:55:25 2010
@@ -27,6 +27,7 @@ import org.apache.ws.security.WSSecurity
 import org.apache.ws.security.util.WSSecurityUtil;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
+import org.w3c.dom.Text;
 
 import javax.crypto.SecretKey;
 import javax.security.auth.callback.Callback;
@@ -78,13 +79,18 @@ public class X509Util {
                 keyInfoElem, "KeyName", WSConstants.SIG_NS
             );
         if (keyNmElem != null) {
-            keyNmElem.normalize();
-            Node tmpN = keyNmElem.getFirstChild();
-            if (tmpN != null && tmpN.getNodeType() == Node.TEXT_NODE) {
-                keyName = tmpN.getNodeValue();
+            
+            Node node = keyNmElem.getFirstChild();
+            StringBuilder builder = new StringBuilder();
+            while (node != null) {
+                if (Node.TEXT_NODE == node.getNodeType()) {
+                    builder.append(((Text)node).getData());
+                }
+                node = node.getNextSibling();
             }
+            keyName = builder.toString();
         }
-        if (keyName == null) {
+        if (keyName == null || keyName.length() <= 0) {
             throw new WSSecurityException(WSSecurityException.INVALID_SECURITY, "noKeyname");
         }
         WSPasswordCallback pwCb = new WSPasswordCallback(keyName, WSPasswordCallback.KEY_NAME);

Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/DerivedKeyTokenSTRParser.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/DerivedKeyTokenSTRParser.java?rev=1051481&r1=1051480&r2=1051481&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/DerivedKeyTokenSTRParser.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/DerivedKeyTokenSTRParser.java Tue Dec 21 12:55:25 2010
@@ -22,7 +22,6 @@ package org.apache.ws.security.str;
 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.components.crypto.Crypto;
@@ -37,22 +36,36 @@ import java.io.IOException;
 import java.security.Principal;
 import java.security.PublicKey;
 import java.security.cert.X509Certificate;
+import java.util.Map;
 
 import javax.security.auth.callback.Callback;
 import javax.security.auth.callback.CallbackHandler;
 import javax.security.auth.callback.UnsupportedCallbackException;
 
+/**
+ * This implementation of STRParser is for parsing a SecurityTokenReference element associated
+ * with a DerivedKeyToken element.
+ */
 public class DerivedKeyTokenSTRParser implements STRParser {
     
     private byte[] secretKey;
     
+    /**
+     * Parse a SecurityTokenReference element and extract credentials.
+     * 
+     * @param strElement The SecurityTokenReference element
+     * @param crypto The crypto instance used to extract credentials
+     * @param cb The CallbackHandler instance to supply passwords
+     * @param wsDocInfo The WSDocInfo object to access previous processing results
+     * @param parameters A set of implementation-specific parameters
+     * @throws WSSecurityException
+     */
     public void parseSecurityTokenReference(
         Element strElement,
-        String algorithm,
         Crypto crypto,
         CallbackHandler cb,
         WSDocInfo wsDocInfo,
-        WSSConfig wssConfig
+        Map<String, Object> parameters
     ) throws WSSecurityException {
         SecurityTokenReference secRef = new SecurityTokenReference(strElement);
         
@@ -114,23 +127,34 @@ public class DerivedKeyTokenSTRParser im
         }
     }
     
-    
-    public void validateCredentials() throws WSSecurityException {
-        //
-    }
-    
+    /**
+     * Get the X509Certificates associated with this SecurityTokenReference
+     * @return the X509Certificates associated with this SecurityTokenReference
+     */
     public X509Certificate[] getCertificates() {
         return null;
     }
     
+    /**
+     * Get the Principal associated with this SecurityTokenReference
+     * @return the Principal associated with this SecurityTokenReference
+     */
     public Principal getPrincipal() {
         return null;
     }
     
+    /**
+     * Get the PublicKey associated with this SecurityTokenReference
+     * @return the PublicKey associated with this SecurityTokenReference
+     */
     public PublicKey getPublicKey() {
         return null;
     }
     
+    /**
+     * Get the Secret Key associated with this SecurityTokenReference
+     * @return the Secret Key associated with this SecurityTokenReference
+     */
     public byte[] getSecretKey() {
         return secretKey;
     }

Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/EncryptedKeySTRParser.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/EncryptedKeySTRParser.java?rev=1051481&r1=1051480&r2=1051481&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/EncryptedKeySTRParser.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/EncryptedKeySTRParser.java Tue Dec 21 12:55:25 2010
@@ -23,7 +23,6 @@ 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.WSSConfig;
 import org.apache.ws.security.WSSecurityEngine;
 import org.apache.ws.security.WSSecurityEngineResult;
 import org.apache.ws.security.WSSecurityException;
@@ -37,31 +36,43 @@ import org.w3c.dom.Element;
 import java.security.Principal;
 import java.security.PublicKey;
 import java.security.cert.X509Certificate;
+import java.util.Map;
 
 import javax.security.auth.callback.CallbackHandler;
 import javax.xml.namespace.QName;
 
+/**
+ * This implementation of STRParser is for parsing a SecurityTokenReference element, found in the
+ * KeyInfo element associated with an EncryptedKey element
+ */
 public class EncryptedKeySTRParser implements STRParser {
     
     private static final Log LOG = LogFactory.getLog(EncryptedKeySTRParser.class.getName());
     
     private X509Certificate[] certs;
     
+    /**
+     * Parse a SecurityTokenReference element and extract credentials.
+     * 
+     * @param strElement The SecurityTokenReference element
+     * @param crypto The crypto instance used to extract credentials
+     * @param cb The CallbackHandler instance to supply passwords
+     * @param wsDocInfo The WSDocInfo object to access previous processing results
+     * @param parameters A set of implementation-specific parameters
+     * @throws WSSecurityException
+     */
     public void parseSecurityTokenReference(
         Element strElement,
-        String algorithm,
         Crypto crypto,
         CallbackHandler cb,
         WSDocInfo wsDocInfo,
-        WSSConfig wssConfig
+        Map<String, Object> parameters
     ) throws WSSecurityException {
         SecurityTokenReference secRef = new SecurityTokenReference(strElement);
         //
-        // handle X509IssuerSerial here. First check if all elements are available,
+        // Handle X509IssuerSerial here. First check if all elements are available,
         // get the appropriate data, check if all data is available.
-        // If all is ok up to that point, look up the certificate alias according
-        // to issuer name and serial number.
-        // This method is recommended by OASIS WS-S specification, X509 profile
+        // Then look up the certificate alias according to issuer name and serial number.
         //
         if (secRef.containsX509Data() || secRef.containsX509IssuerSerial()) {
             String alias = secRef.getX509IssuerSerialAlias(crypto);
@@ -149,23 +160,34 @@ public class EncryptedKeySTRParser imple
         }
     }
     
-    
-    public void validateCredentials() throws WSSecurityException {
-        //
-    }
-    
+    /**
+     * Get the X509Certificates associated with this SecurityTokenReference
+     * @return the X509Certificates associated with this SecurityTokenReference
+     */
     public X509Certificate[] getCertificates() {
         return certs;
     }
     
+    /**
+     * Get the Principal associated with this SecurityTokenReference
+     * @return the Principal associated with this SecurityTokenReference
+     */
     public Principal getPrincipal() {
         return null;
     }
     
+    /**
+     * Get the PublicKey associated with this SecurityTokenReference
+     * @return the PublicKey associated with this SecurityTokenReference
+     */
     public PublicKey getPublicKey() {
         return null;
     }
     
+    /**
+     * Get the Secret Key associated with this SecurityTokenReference
+     * @return the Secret Key associated with this SecurityTokenReference
+     */
     public byte[] getSecretKey() {
         return null;
     }

Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/STRParser.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/STRParser.java?rev=1051481&r1=1051480&r2=1051481&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/STRParser.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/STRParser.java Tue Dec 21 12:55:25 2010
@@ -20,7 +20,6 @@
 package org.apache.ws.security.str;
 
 import org.apache.ws.security.WSDocInfo;
-import org.apache.ws.security.WSSConfig;
 import org.apache.ws.security.WSSecurityException;
 import org.apache.ws.security.components.crypto.Crypto;
 import org.w3c.dom.Element;
@@ -28,27 +27,55 @@ import org.w3c.dom.Element;
 import java.security.Principal;
 import java.security.PublicKey;
 import java.security.cert.X509Certificate;
+import java.util.Map;
 import javax.security.auth.callback.CallbackHandler;
 
+/**
+ * This interface describes a pluggable way of extracting credentials from SecurityTokenReference
+ * elements. The implementations are used by various processors.
+ */
 public interface STRParser {
     
+    /**
+     * Parse a SecurityTokenReference element and extract credentials.
+     * 
+     * @param strElement The SecurityTokenReference element
+     * @param crypto The crypto instance used to extract credentials
+     * @param cb The CallbackHandler instance to supply passwords
+     * @param wsDocInfo The WSDocInfo object to access previous processing results
+     * @param parameters A set of implementation-specific parameters
+     * @throws WSSecurityException
+     */
     public void parseSecurityTokenReference(
         Element strElement,
-        String algorithm,
         Crypto crypto,
         CallbackHandler cb,
         WSDocInfo wsDocInfo,
-        WSSConfig wssConfig
+        Map<String, Object> parameters
     ) throws WSSecurityException;
     
-    public void validateCredentials() throws WSSecurityException;
-    
+    /**
+     * Get the X509Certificates associated with this SecurityTokenReference
+     * @return the X509Certificates associated with this SecurityTokenReference
+     */
     public X509Certificate[] getCertificates();
     
+    /**
+     * Get the Principal associated with this SecurityTokenReference
+     * @return the Principal associated with this SecurityTokenReference
+     */
     public Principal getPrincipal();
     
+    /**
+     * Get the PublicKey associated with this SecurityTokenReference
+     * @return the PublicKey associated with this SecurityTokenReference
+     */
     public PublicKey getPublicKey();
     
+    /**
+     * Get the Secret Key associated with this SecurityTokenReference
+     * @return the Secret Key associated with this SecurityTokenReference
+     */
     public byte[] getSecretKey();
     
 }

Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/SecurityTokenRefSTRParser.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/SecurityTokenRefSTRParser.java?rev=1051481&r1=1051480&r2=1051481&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/SecurityTokenRefSTRParser.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/SecurityTokenRefSTRParser.java Tue Dec 21 12:55:25 2010
@@ -22,7 +22,6 @@ package org.apache.ws.security.str;
 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.components.crypto.Crypto;
@@ -37,21 +36,40 @@ import org.w3c.dom.Element;
 import java.security.Principal;
 import java.security.PublicKey;
 import java.security.cert.X509Certificate;
+import java.util.Map;
 
 import javax.security.auth.callback.Callback;
 import javax.security.auth.callback.CallbackHandler;
 
+/**
+ * This implementation of STRParser is for parsing a SecurityTokenReference element, found in the
+ * KeyInfo element associated with an EncryptedData element.
+ */
 public class SecurityTokenRefSTRParser implements STRParser {
     
+    /**
+     * The Signature method. This is used when deriving a key.
+     */
+    public static final String SIGNATURE_METHOD = "signature_method";
+    
     private byte[] secretKey;
     
+    /**
+     * Parse a SecurityTokenReference element and extract credentials.
+     * 
+     * @param strElement The SecurityTokenReference element
+     * @param crypto The crypto instance used to extract credentials
+     * @param cb The CallbackHandler instance to supply passwords
+     * @param wsDocInfo The WSDocInfo object to access previous processing results
+     * @param parameters A set of implementation-specific parameters
+     * @throws WSSecurityException
+     */
     public void parseSecurityTokenReference(
         Element strElement,
-        String algorithm,
         Crypto crypto,
         CallbackHandler cb,
         WSDocInfo wsDocInfo,
-        WSSConfig wssConfig
+        Map<String, Object> parameters
     ) throws WSSecurityException {
 
         SecurityTokenReference secRef = new SecurityTokenReference(strElement);
@@ -73,6 +91,7 @@ public class SecurityTokenRefSTRParser i
                         (DerivedKeyToken)result.get(WSSecurityEngineResult.TAG_DERIVED_KEY_TOKEN);
                     byte[] secret = 
                         (byte[])result.get(WSSecurityEngineResult.TAG_SECRET);
+                    String algorithm = (String)parameters.get(SIGNATURE_METHOD);
                     secretKey = dkt.deriveKey(WSSecurityUtil.getKeyLength(algorithm), secret);
                 } else if (WSConstants.ST_UNSIGNED == action) {
                     Element samlElement = wsDocInfo.getTokenElement(id);
@@ -149,23 +168,34 @@ public class SecurityTokenRefSTRParser i
         }
     }
     
-    
-    public void validateCredentials() throws WSSecurityException {
-        //
-    }
-    
+    /**
+     * Get the X509Certificates associated with this SecurityTokenReference
+     * @return the X509Certificates associated with this SecurityTokenReference
+     */
     public X509Certificate[] getCertificates() {
         return null;
     }
     
+    /**
+     * Get the Principal associated with this SecurityTokenReference
+     * @return the Principal associated with this SecurityTokenReference
+     */
     public Principal getPrincipal() {
         return null;
     }
     
+    /**
+     * Get the PublicKey associated with this SecurityTokenReference
+     * @return the PublicKey associated with this SecurityTokenReference
+     */
     public PublicKey getPublicKey() {
         return null;
     }
     
+    /**
+     * Get the Secret Key associated with this SecurityTokenReference
+     * @return the Secret Key associated with this SecurityTokenReference
+     */
     public byte[] getSecretKey() {
         return secretKey;
     }

Modified: webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/SignatureSTRParser.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/SignatureSTRParser.java?rev=1051481&r1=1051480&r2=1051481&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/SignatureSTRParser.java (original)
+++ webservices/wss4j/trunk/src/main/java/org/apache/ws/security/str/SignatureSTRParser.java Tue Dec 21 12:55:25 2010
@@ -19,13 +19,10 @@
 
 package org.apache.ws.security.str;
 
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
 import org.apache.ws.security.CustomTokenPrincipal;
 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.WSSecurityEngine;
 import org.apache.ws.security.WSSecurityEngineResult;
 import org.apache.ws.security.WSSecurityException;
@@ -44,21 +41,32 @@ import org.apache.ws.security.util.WSSec
 import org.opensaml.SAMLAssertion;
 import org.w3c.dom.Element;
 
-import java.math.BigInteger;
 import java.security.Principal;
 import java.security.PublicKey;
-import java.security.cert.CertificateExpiredException;
-import java.security.cert.CertificateNotYetValidException;
 import java.security.cert.X509Certificate;
 import java.util.List;
+import java.util.Map;
 
 import javax.security.auth.callback.Callback;
 import javax.security.auth.callback.CallbackHandler;
 import javax.xml.namespace.QName;
 
+/**
+ * This implementation of STRParser is for parsing a SecurityTokenReference element, found in the
+ * KeyInfo element associated with a Signature element.
+ */
 public class SignatureSTRParser implements STRParser {
     
-    private static final Log LOG = LogFactory.getLog(SignatureSTRParser.class.getName());
+    /**
+     * The Signature method. This is used when deriving a key to use for verifying the signature.
+     */
+    public static final String SIGNATURE_METHOD = "signature_method";
+    
+    /**
+     * The secret key length. This is used when deriving a key from a Username token for the
+     * non-standard WSE implementation.
+     */
+    public static final String SECRET_KEY_LENGTH = "secret_key_length";
     
     private X509Certificate[] certs;
     
@@ -68,19 +76,23 @@ public class SignatureSTRParser implemen
     
     private Principal principal;
     
-    private boolean validateCertChain;
-    
-    private Crypto crypto;
-    
+    /**
+     * Parse a SecurityTokenReference element and extract credentials.
+     * 
+     * @param strElement The SecurityTokenReference element
+     * @param crypto The crypto instance used to extract credentials
+     * @param cb The CallbackHandler instance to supply passwords
+     * @param wsDocInfo The WSDocInfo object to access previous processing results
+     * @param parameters A set of implementation-specific parameters
+     * @throws WSSecurityException
+     */
     public void parseSecurityTokenReference(
         Element strElement,
-        String algorithm,
         Crypto crypto,
         CallbackHandler cb,
         WSDocInfo wsDocInfo,
-        WSSConfig wssConfig
+        Map<String, Object> parameters
     ) throws WSSecurityException {
-        this.crypto = crypto;
         SecurityTokenReference secRef = new SecurityTokenReference(strElement);
         //
         // Here we get some information about the document that is being
@@ -101,9 +113,6 @@ public class SignatureSTRParser implemen
                 QName el = new QName(token.getNamespaceURI(), token.getLocalName());
                 if (el.equals(WSSecurityEngine.BINARY_TOKEN)) {
                     certs = getCertificatesTokenReference(token, crypto);
-                    if (certs != null && certs.length > 1) {
-                        validateCertChain = true;
-                    }
                 } else if (el.equals(WSSecurityEngine.SAML_TOKEN)) {
                     if (crypto == null) {
                         throw new WSSecurityException(
@@ -111,7 +120,10 @@ public class SignatureSTRParser implemen
                         );
                     }
                     SAMLKeyInfo samlKi = SAMLUtil.getSAMLKeyInfo(token, crypto, cb);
-                    certs = samlKi.getCerts();
+                    X509Certificate[] foundCerts = samlKi.getCerts();
+                    if (foundCerts != null) {
+                        certs = new X509Certificate[]{foundCerts[0]};
+                    }
                     secretKey = samlKi.getSecret();
                     principal = createPrincipalFromSAMLKeyInfo(samlKi);
                 } else if (el.equals(WSSecurityEngine.ENCRYPTED_KEY)){
@@ -139,15 +151,13 @@ public class SignatureSTRParser implemen
                     if (usernameToken.isDerivedKey()) {
                         secretKey = usernameToken.getDerivedKey();
                     } else {
-                        secretKey = usernameToken.getSecretKey(wssConfig.getSecretKeyLength());
+                        int keyLength = ((Integer)parameters.get(SECRET_KEY_LENGTH)).intValue();
+                        secretKey = usernameToken.getSecretKey(keyLength);
                     }
                     principal = usernameToken.createPrincipal();
                 } else if (WSConstants.BST == action) {
                     certs = 
                         (X509Certificate[])result.get(WSSecurityEngineResult.TAG_X509_CERTIFICATES);
-                    if (certs != null && certs.length > 1) {
-                        validateCertChain = true;
-                    }
                 } else if (WSConstants.ENCR == action) {
                     secretKey = (byte[])result.get(WSSecurityEngineResult.TAG_DECRYPTED_KEY);
                     String id = (String)result.get(WSSecurityEngineResult.TAG_ID);
@@ -164,6 +174,7 @@ public class SignatureSTRParser implemen
                         (DerivedKeyToken)result.get(WSSecurityEngineResult.TAG_DERIVED_KEY_TOKEN);
                     int keyLength = dkt.getLength();
                     if (keyLength <= 0) {
+                        String algorithm = (String)parameters.get(SIGNATURE_METHOD);
                         keyLength = WSSecurityUtil.getKeyLength(algorithm);
                     }
                     byte[] secret = (byte[])result.get(WSSecurityEngineResult.TAG_SECRET);
@@ -178,14 +189,20 @@ public class SignatureSTRParser implemen
                     Element samlElement = wsDocInfo.getTokenElement(uri);
                     SAMLKeyInfo keyInfo = 
                         SAMLUtil.getSAMLKeyInfo(samlElement, crypto, cb);
-                    certs = keyInfo.getCerts();
+                    X509Certificate[] foundCerts = keyInfo.getCerts();
+                    if (foundCerts != null) {
+                        certs = new X509Certificate[]{foundCerts[0]};
+                    }
                     secretKey = keyInfo.getSecret();
                     publicKey = keyInfo.getPublicKey();
                     principal = createPrincipalFromSAMLKeyInfo(keyInfo);
                 }
             }
         } else if (secRef.containsX509Data() || secRef.containsX509IssuerSerial()) {
-            certs = secRef.getX509IssuerSerial(crypto);
+            X509Certificate[] foundCerts = secRef.getX509IssuerSerial(crypto);
+            if (foundCerts != null) {
+                certs = new X509Certificate[]{foundCerts[0]};
+            }
         } else if (secRef.containsKeyIdentifier()) {
             if (secRef.getKeyIdentifierValueType().equals(SecurityTokenReference.ENC_KEY_SHA1_URI)) {
                 String id = secRef.getKeyIdentifierValue();
@@ -201,12 +218,18 @@ public class SignatureSTRParser implemen
                     );
                 }
                 SAMLKeyInfo samlKi = SAMLUtil.getSAMLKeyInfo(token, crypto, cb);
-                certs = samlKi.getCerts();
+                X509Certificate[] foundCerts = samlKi.getCerts();
+                if (foundCerts != null) {
+                    certs = new X509Certificate[]{foundCerts[0]};
+                }
                 secretKey = samlKi.getSecret();
                 publicKey = samlKi.getPublicKey();
                 principal = createPrincipalFromSAMLKeyInfo(samlKi);
             } else {
-                certs = secRef.getKeyIdentifier(crypto);
+                X509Certificate[] foundCerts = secRef.getKeyIdentifier(crypto);
+                if (foundCerts != null) {
+                    certs = new X509Certificate[]{foundCerts[0]};
+                }
             }
         } else {
             throw new WSSecurityException(
@@ -215,224 +238,42 @@ public class SignatureSTRParser implemen
                     new Object[]{strElement.toString()}
             );
         }
-    }
-    
-    public void validateCredentials() throws WSSecurityException {
-        //
-        // Validate certificates and verify trust
-        //
-        validateCertificates(certs);
-        if (certs != null) {
-            if (principal == null) {
-                principal = certs[0].getSubjectX500Principal();
-            }
-            boolean trust = false;
-            if (!validateCertChain || certs.length == 1) {
-                trust = verifyTrust(certs[0], crypto);
-            } else if (validateCertChain && certs.length > 1) {
-                trust = verifyTrust(certs, crypto);
-            }
-            if (!trust) {
-                throw new WSSecurityException(WSSecurityException.FAILED_CHECK);
-            }
+        
+        if (certs != null && principal == null) {
+            principal = certs[0].getSubjectX500Principal();
         }
     }
     
+    /**
+     * Get the X509Certificates associated with this SecurityTokenReference
+     * @return the X509Certificates associated with this SecurityTokenReference
+     */
     public X509Certificate[] getCertificates() {
         return certs;
     }
     
-    public Principal getPrincipal() {
-        return principal;
-    }
-    
-    public PublicKey getPublicKey() {
-        return publicKey;
-    }
-    
-    public byte[] getSecretKey() {
-        return secretKey;
-    }
-    
     /**
-     * Validate an array of certificates by checking the validity of each cert
-     * @param certsToValidate The array of certificates to validate
-     * @throws WSSecurityException
+     * Get the Principal associated with this SecurityTokenReference
+     * @return the Principal associated with this SecurityTokenReference
      */
-    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
-                );
-            }
-        }
+    public Principal getPrincipal() {
+        return principal;
     }
     
-    
     /**
-     * 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
+     * Get the PublicKey associated with this SecurityTokenReference
+     * @return the PublicKey associated with this SecurityTokenReference
      */
-    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;
+    public PublicKey getPublicKey() {
+        return publicKey;
     }
     
-
     /**
-     * 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
+     * Get the Secret Key associated with this SecurityTokenReference
+     * @return the Secret Key associated with this SecurityTokenReference
      */
-    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;
+    public byte[] getSecretKey() {
+        return secretKey;
     }
     
     
@@ -537,7 +378,6 @@ public class SignatureSTRParser implemen
         return pwcb.getKey();
     }
     
-    
     /**
      * Get the Secret Key from a CallbackHandler for the Encrypted Key SHA1 case.
      * @param id The id of the element



Mime
View raw message