You are viewing a plain text version of this content. The canonical link for it is here.
Posted to wss4j-dev@ws.apache.org by co...@apache.org on 2010/05/17 16:22:03 UTC

svn commit: r945177 - in /webservices/wss4j/trunk: src/org/apache/ws/security/processor/ src/org/apache/ws/security/transform/ test/ test/wssec/

Author: coheigea
Date: Mon May 17 14:22:02 2010
New Revision: 945177

URL: http://svn.apache.org/viewvc?rev=945177&view=rev
Log:
[WSS-222] - Applied patch for "SignatureProcessor does not provide correct signature coverage results with STR Dereference Transform"
 - Thanks to David for the patch and test-case.
 - This took me a while to modify, due to the use of JSR-105 on trunk.

Added:
    webservices/wss4j/trunk/src/org/apache/ws/security/transform/STRTransformUtil.java   (with props)
Modified:
    webservices/wss4j/trunk/src/org/apache/ws/security/processor/SignatureProcessor.java
    webservices/wss4j/trunk/src/org/apache/ws/security/transform/STRTransform.java
    webservices/wss4j/trunk/test/log4j.properties
    webservices/wss4j/trunk/test/wssec/TestWSSecuritySignatureParts.java

Modified: webservices/wss4j/trunk/src/org/apache/ws/security/processor/SignatureProcessor.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/processor/SignatureProcessor.java?rev=945177&r1=945176&r2=945177&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/org/apache/ws/security/processor/SignatureProcessor.java (original)
+++ webservices/wss4j/trunk/src/org/apache/ws/security/processor/SignatureProcessor.java Mon May 17 14:22:02 2010
@@ -43,20 +43,25 @@ import org.apache.ws.security.message.to
 import org.apache.ws.security.message.token.X509Security;
 import org.apache.ws.security.saml.SAMLKeyInfo;
 import org.apache.ws.security.saml.SAMLUtil;
+import org.apache.ws.security.transform.STRApacheTransform;
+import org.apache.ws.security.transform.STRTransformUtil;
 import org.apache.ws.security.util.WSSecurityUtil;
 
 import org.opensaml.SAMLAssertion;
 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;
+import javax.xml.crypto.NodeSetData;
 import javax.xml.crypto.XMLStructure;
 import javax.xml.crypto.dom.DOMStructure;
 import javax.xml.crypto.dsig.Reference;
 import javax.xml.crypto.dsig.SignedInfo;
+import javax.xml.crypto.dsig.Transform;
 import javax.xml.crypto.dsig.XMLSignature;
 import javax.xml.crypto.dsig.XMLSignatureFactory;
 import javax.xml.crypto.dsig.XMLValidateContext;
@@ -381,6 +386,7 @@ public class SignatureProcessor implemen
             key = WSSecurityUtil.prepareSecretKey(signatureMethod, secretKey);
         }
         XMLValidateContext context = new DOMValidateContext(key, elem);
+        context.setProperty("javax.xml.crypto.dsig.cacheReference", Boolean.TRUE);
         try {
             XMLSignature xmlSignature = signatureFactory.unmarshalXMLSignature(context);
             boolean signatureOk = xmlSignature.validate(context);
@@ -388,7 +394,7 @@ public class SignatureProcessor implemen
                 signatureValue = xmlSignature.getSignatureValue().getValue();
                 protectedRefs = 
                     buildProtectedRefs(
-                        elem.getOwnerDocument(), xmlSignature.getSignedInfo(), protectedRefs
+                        elem.getOwnerDocument(), xmlSignature.getSignedInfo(), wsDocInfo, protectedRefs
                     );
                 
                 return principal;
@@ -778,15 +784,50 @@ public class SignatureProcessor implemen
      */
     private static List buildProtectedRefs(
         Document doc,
-        SignedInfo signedInfo, 
+        SignedInfo signedInfo,
+        WSDocInfo wsDocInfo,
         List protectedRefs
     ) throws WSSecurityException {
         List referencesList = signedInfo.getReferences();
         for (int i = 0; i < referencesList.size(); i++) {
             Reference siRef = (Reference)referencesList.get(i);
             String uri = siRef.getURI();
+            
             if (!"".equals(uri)) {
-                Element se = WSSecurityUtil.getElementByWsuId(doc, uri);
+                Element se = null;
+                
+                List transformsList = siRef.getTransforms();
+                
+                for (int j = 0; j < transformsList.size(); j++) {
+                    
+                    Transform transform = (Transform)transformsList.get(j);
+                    
+                    if (STRApacheTransform.TRANSFORM_URI.equals(transform.getAlgorithm())) {
+                        NodeSetData data = (NodeSetData)siRef.getDereferencedData();
+                        if (data != null) {
+                            java.util.Iterator iter = data.iterator();
+                            
+                            Node securityTokenReference = null;
+                            while (iter.hasNext()) {
+                                Node node = (Node)iter.next();
+                                if ("SecurityTokenReference".equals(node.getLocalName())) {
+                                    securityTokenReference = node;
+                                    break;
+                                }
+                            }
+                            
+                            if (securityTokenReference != null) {
+                                SecurityTokenReference secTokenRef = 
+                                    new SecurityTokenReference((Element)securityTokenReference);
+                                se = STRTransformUtil.dereferenceSTR(doc, secTokenRef, wsDocInfo);
+                            }
+                        }
+                    }
+                }
+                
+                if (se == null) {
+                    se = WSSecurityUtil.getElementByWsuId(doc, uri);
+                }
                 if (se == null) {
                     se = WSSecurityUtil.getElementByGenId(doc, uri);
                 }

Modified: webservices/wss4j/trunk/src/org/apache/ws/security/transform/STRTransform.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/transform/STRTransform.java?rev=945177&r1=945176&r2=945177&view=diff
==============================================================================
--- webservices/wss4j/trunk/src/org/apache/ws/security/transform/STRTransform.java (original)
+++ webservices/wss4j/trunk/src/org/apache/ws/security/transform/STRTransform.java Mon May 17 14:22:02 2010
@@ -26,7 +26,6 @@ import org.apache.ws.security.WSDocInfo;
 import org.apache.ws.security.WSDocInfoStore;
 import org.apache.ws.security.WSSecurityException;
 import org.apache.ws.security.message.token.SecurityTokenReference;
-import org.apache.ws.security.message.token.X509Security;
 import org.apache.ws.security.util.WSSecurityUtil;
 import org.apache.xml.security.c14n.CanonicalizationException;
 import org.apache.xml.security.c14n.Canonicalizer;
@@ -34,17 +33,13 @@ import org.apache.xml.security.c14n.Inva
 import org.apache.xml.security.signature.XMLSignatureInput;
 import org.apache.xml.security.transforms.Transform;
 import org.apache.xml.security.transforms.TransformSpi;
-import org.apache.ws.security.util.Base64;
 import org.apache.xml.security.utils.XMLUtils;
 
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
-import org.w3c.dom.Text;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.X509Certificate;
 
 
 /**
@@ -187,7 +182,8 @@ public class STRTransform extends Transf
             //
             // Third and fourth step are performed by derefenceSTR()
             //
-            Element dereferencedToken = dereferenceSTR(thisDoc, secRef);
+            Element dereferencedToken = STRTransformUtil.dereferenceSTR(
+                    thisDoc, secRef, wsDocInfo);
             //
             // C14n with specified algorithm. According to WSS Specification.
             //
@@ -250,92 +246,4 @@ public class STRTransform extends Transf
             throw (new CanonicalizationException("c14n.Canonicalizer.Exception", ex));
         }
     }
-
-    private Element dereferenceSTR(Document doc, SecurityTokenReference secRef)
-        throws WSSecurityException {
-        //
-        // Third step: locate the security token referenced by the STR element.
-        // Either the Token is contained in the document as a
-        // BinarySecurityToken or stored in some key storage.
-        // 
-        // Fourth step: after security token was located, prepare it. If its
-        // reference via a direct reference, i.e. a relative URI that references
-        // the BST directly in the message then just return that element.
-        // Otherwise wrap the located token in a newly created BST element as
-        // described in WSS Specification.
-        // 
-        //
-        Element tokElement = null;
-
-        //
-        // First case: direct reference, according to chap 7.2 of OASIS WS
-        // specification (main document). Only in this case return a true
-        // reference to the BST. Copying is done by the caller.
-        //
-        if (secRef.containsReference()) {
-            if (doDebug) {
-                log.debug("STR: Reference");
-            }
-            tokElement = secRef.getTokenElement(doc, wsDocInfo, null);
-        }
-        //
-        // second case: IssuerSerial, lookup in keystore, wrap in BST according
-        // to specification
-        //
-        else if (secRef.containsX509Data() || secRef.containsX509IssuerSerial()) {
-            if (doDebug) {
-                log.debug("STR: IssuerSerial");
-            }
-            X509Certificate cert = null;
-            X509Certificate[] certs = 
-                secRef.getX509IssuerSerial(wsDocInfo.getCrypto());
-            if (certs == null || certs.length == 0 || certs[0] == null) {
-                throw new WSSecurityException(WSSecurityException.FAILED_CHECK);
-            }
-            cert = certs[0];
-            tokElement = createBSTX509(doc, cert, secRef.getElement());
-        }
-        //
-        // third case: KeyIdentifier. For SKI, lookup in keystore, wrap in
-        // BST according to specification. Otherwise if it's a wsse:KeyIdentifier it could
-        // be a SAML assertion, so try and find the referenced element.
-        //
-        else if (secRef.containsKeyIdentifier()) {
-            if (doDebug) {
-                log.debug("STR: KeyIdentifier");
-            }
-            if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(secRef.getKeyIdentifierValueType())) {
-                tokElement = secRef.getKeyIdentifierTokenElement(doc, wsDocInfo, null);
-            } else {
-                X509Certificate cert = null;
-                X509Certificate[] certs = secRef.getKeyIdentifier(wsDocInfo.getCrypto());
-                if (certs == null || certs.length == 0 || certs[0] == null) {
-                    throw new WSSecurityException(WSSecurityException.FAILED_CHECK);
-                }
-                cert = certs[0];
-                tokElement = createBSTX509(doc, cert, secRef.getElement());
-            }
-        }
-        return tokElement;
-    }
-
-    private Element createBSTX509(Document doc, X509Certificate cert, Element secRefE) 
-        throws WSSecurityException {
-        byte data[];
-        try {
-            data = cert.getEncoded();
-        } catch (CertificateEncodingException e) {
-            throw new WSSecurityException(
-                WSSecurityException.SECURITY_TOKEN_UNAVAILABLE, "encodeError", null, e
-            );
-        }
-        String prefix = 
-            WSSecurityUtil.setNamespace(secRefE, WSConstants.WSSE_NS, WSConstants.WSSE_PREFIX);
-        Element elem = doc.createElementNS(WSConstants.WSSE_NS, prefix + ":BinarySecurityToken");
-        elem.setAttributeNS(null, "ValueType", X509Security.X509_V3_TYPE);
-        Text certText = doc.createTextNode(Base64.encode(data)); // no line wrap
-        elem.appendChild(certText);
-        return elem;
-    }
-    
 }

Added: webservices/wss4j/trunk/src/org/apache/ws/security/transform/STRTransformUtil.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/src/org/apache/ws/security/transform/STRTransformUtil.java?rev=945177&view=auto
==============================================================================
--- webservices/wss4j/trunk/src/org/apache/ws/security/transform/STRTransformUtil.java (added)
+++ webservices/wss4j/trunk/src/org/apache/ws/security/transform/STRTransformUtil.java Mon May 17 14:22:02 2010
@@ -0,0 +1,156 @@
+/**
+ * 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.transform;
+
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+
+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.WSSecurityException;
+import org.apache.ws.security.message.token.SecurityTokenReference;
+import org.apache.ws.security.message.token.X509Security;
+import org.apache.ws.security.util.Base64;
+import org.apache.ws.security.util.WSSecurityUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Text;
+
+/**
+ * Utility class exposing the dereferencing logic of the {@link STRTransform} implementation.
+ */
+public class STRTransformUtil {
+    private static Log log = LogFactory.getLog(STRTransformUtil.class.getName());
+
+    /**
+     * Retrieves the element representing the referenced content of a STR.
+     * 
+     * @return the element representing the referenced content. The element is either
+     *         extracted from {@code doc} or a new element is created in the
+     *         case of a key identifier or issuer serial STR.  {@code null} if
+     *         {@code secRef} does not contain a direct reference, key identifier, or
+     *         issuer serial.
+     * @throws WSSecurityException
+     *             If an issuer serial or key identifier is used in the STR and
+     *             the certificate cannot be resolved from the crypto
+     *             configuration or if there is an error working with the resolved
+     *             cert
+     */
+    public static Element dereferenceSTR(Document doc,
+            SecurityTokenReference secRef, WSDocInfo wsDocInfo) throws WSSecurityException
+    {
+        
+        // NOTE: Here step numbers refer to the overall step in the complete processing
+        // of the STRTransform.  See STRTransform for the lead up to these steps.
+        //
+        // Third step: locate the security token referenced by the STR element.
+        // Either the Token is contained in the document as a
+        // BinarySecurityToken or stored in some key storage.
+        // 
+        // Fourth step: after security token was located, prepare it. If its
+        // reference via a direct reference, i.e. a relative URI that references
+        // the BST directly in the message then just return that element.
+        // Otherwise wrap the located token in a newly created BST element as
+        // described in WSS Specification.
+        // 
+        //
+        Element tokElement = null;
+    
+        //
+        // First case: direct reference, according to chap 7.2 of OASIS WS
+        // specification (main document). Only in this case return a true
+        // reference to the BST. Copying is done by the caller.
+        //
+        if (secRef.containsReference()) {
+            if (log.isDebugEnabled()) {
+                log.debug("STR: Reference");
+            }
+            tokElement = secRef.getTokenElement(doc, wsDocInfo, null);
+        }
+        //
+        // second case: IssuerSerial, lookup in keystore, wrap in BST according
+        // to specification
+        //
+        else if (secRef.containsX509Data() || secRef.containsX509IssuerSerial()) {
+            if (log.isDebugEnabled()) {
+                log.debug("STR: IssuerSerial");
+            }
+            X509Certificate cert = null;
+            X509Certificate[] certs = 
+                secRef.getX509IssuerSerial(wsDocInfo.getCrypto());
+            if (certs == null || certs.length == 0 || certs[0] == null) {
+                throw new WSSecurityException(WSSecurityException.FAILED_CHECK);
+            }
+            cert = certs[0];
+            tokElement = createBSTX509(doc, cert, secRef.getElement());
+        }
+        //
+        // third case: KeyIdentifier. For SKI, lookup in keystore, wrap in
+        // BST according to specification. Otherwise if it's a wsse:KeyIdentifier it could
+        // be a SAML assertion, so try and find the referenced element.
+        //
+        else if (secRef.containsKeyIdentifier()) {
+            if (log.isDebugEnabled()) {
+                log.debug("STR: KeyIdentifier");
+            }
+            if (WSConstants.WSS_SAML_KI_VALUE_TYPE.equals(secRef.getKeyIdentifierValueType())) {
+                tokElement = secRef.getKeyIdentifierTokenElement(doc, wsDocInfo, null);
+            } else {
+                X509Certificate cert = null;
+                X509Certificate[] certs = secRef.getKeyIdentifier(wsDocInfo.getCrypto());
+                if (certs == null || certs.length == 0 || certs[0] == null) {
+                    throw new WSSecurityException(WSSecurityException.FAILED_CHECK);
+                }
+                cert = certs[0];
+                tokElement = createBSTX509(doc, cert, secRef.getElement());
+            }
+        }
+        return tokElement;
+    }
+    
+    protected static Element createBSTX509(Document doc, X509Certificate cert, Element secRefE) 
+        throws WSSecurityException {
+        byte data[];
+        try {
+            data = cert.getEncoded();
+        } catch (CertificateEncodingException e) {
+            throw new WSSecurityException(
+                WSSecurityException.SECURITY_TOKEN_UNAVAILABLE, "encodeError", null, e
+            );
+        }
+        String prefix = WSSecurityUtil.getPrefixNS(WSConstants.WSSE_NS, secRefE);
+        Element elem = doc.createElementNS(WSConstants.WSSE_NS, prefix + ":BinarySecurityToken");
+        WSSecurityUtil.setNamespace(elem, WSConstants.WSSE_NS, prefix);
+        // elem.setAttributeNS(WSConstants.XMLNS_NS, "xmlns", "");
+        elem.setAttributeNS(null, "ValueType", X509Security.X509_V3_TYPE);
+        Text certText = doc.createTextNode(Base64.encode(data)); // no line wrap
+        elem.appendChild(certText);
+        return elem;
+    }
+    
+    /**
+     * Hidden in utility class.
+     */
+    private STRTransformUtil() {   
+    }
+    
+}
\ No newline at end of file

Propchange: webservices/wss4j/trunk/src/org/apache/ws/security/transform/STRTransformUtil.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: webservices/wss4j/trunk/src/org/apache/ws/security/transform/STRTransformUtil.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: webservices/wss4j/trunk/test/log4j.properties
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/test/log4j.properties?rev=945177&r1=945176&r2=945177&view=diff
==============================================================================
--- webservices/wss4j/trunk/test/log4j.properties (original)
+++ webservices/wss4j/trunk/test/log4j.properties Mon May 17 14:22:02 2010
@@ -43,6 +43,7 @@
 # log4j.logger.wssec.TestWSSecurityNew9=DEBUG
 # log4j.logger.wssec.TestWSSecurity10=DEBUG
 # log4j.logger.wssec.TestWSSecurity11=DEBUG
+# log4j.logger.wssec.TestWSSecurityNew11=DEBUG
 # log4j.logger.wssec.TestWSSecurity12=DEBUG
 # log4j.logger.wssec.TestWSSecurity13=DEBUG
 # log4j.logger.wssec.TestWSSecurity14=DEBUG
@@ -54,6 +55,7 @@
 # log4j.logger.wssec.TestWSSecurityST3=DEBUG
 # log4j.logger.wssec.TestWSSecurityNewST3=DEBUG
 # log4j.logger.wssec.TestWSSecuritySOAP12=DEBUG
+# log4j.logger.wssec.TestWSSecuritySignatureParts=DEBUG
 # log4j.logger.org.apache.ws.security.handler.WSS4JHandler=DEBUG
 # log4j.logger.org.apache.ws.security.handler.WSHandler=DEBUG
 log4j.logger.policy.WSSPolicyTesterAsymm=DEBUG

Modified: webservices/wss4j/trunk/test/wssec/TestWSSecuritySignatureParts.java
URL: http://svn.apache.org/viewvc/webservices/wss4j/trunk/test/wssec/TestWSSecuritySignatureParts.java?rev=945177&r1=945176&r2=945177&view=diff
==============================================================================
--- webservices/wss4j/trunk/test/wssec/TestWSSecuritySignatureParts.java (original)
+++ webservices/wss4j/trunk/test/wssec/TestWSSecuritySignatureParts.java Mon May 17 14:22:02 2010
@@ -36,7 +36,11 @@ import org.apache.ws.security.components
 import org.apache.ws.security.components.crypto.CryptoFactory;
 import org.apache.ws.security.message.WSSecSignature;
 import org.apache.ws.security.message.WSSecHeader;
+import org.apache.ws.security.saml.SAMLIssuer;
+import org.apache.ws.security.saml.SAMLIssuerFactory;
+import org.apache.ws.security.saml.WSSecSignatureSAML;
 import org.apache.ws.security.util.WSSecurityUtil;
+import org.opensaml.SAMLAssertion;
 import org.w3c.dom.Document;
 
 import javax.security.auth.callback.Callback;
@@ -147,6 +151,66 @@ public class TestWSSecuritySignaturePart
     }
     
     /**
+     * Test signing of a header through a STR Dereference Transform
+     */
+    public void testSOAPHeaderSTRTransform() throws Exception {
+        Document doc = SOAPUtil.toSOAPPart(SOAPMSG);
+        
+        SAMLIssuer saml = SAMLIssuerFactory.getInstance("saml4.properties");
+        // Provide info to SAML issuer that it can construct a Holder-of-key
+        // SAML token.
+        saml.setInstanceDoc(doc);
+        saml.setUserCrypto(crypto);
+        saml.setUsername("16c73ab6-b892-458f-abf5-2f875f74882e");
+        SAMLAssertion assertion = saml.newAssertion();
+
+        WSSecSignatureSAML wsSign = new WSSecSignatureSAML();
+        wsSign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
+        wsSign.setUserInfo("16c73ab6-b892-458f-abf5-2f875f74882e", "security");
+        
+        WSSecHeader secHeader = new WSSecHeader();
+        secHeader.insertSecurityHeader(doc);
+        
+        List parts = new Vector();
+        WSEncryptionPart encP =
+            new WSEncryptionPart("STRTransform", "", "Element");
+        parts.add(encP);
+        wsSign.setParts(parts);
+
+        LOG.info("Before SAMLSignedKeyHolder....");
+        
+        //
+        // set up for keyHolder
+        //
+        Document signedDoc = wsSign.build(doc, crypto, assertion, null, null, null, secHeader);
+        LOG.info("After SAMLSignedKeyHolder....");
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Signed SAML message (key holder):");
+            String outputString = 
+                org.apache.ws.security.util.XMLUtils.PrettyDocumentToString(signedDoc);
+            LOG.debug(outputString);
+        }
+        
+        List results = verify(signedDoc);
+        WSSecurityEngineResult stUnsignedActionResult =
+            WSSecurityUtil.fetchActionResult(results, WSConstants.ST_UNSIGNED);
+        SAMLAssertion receivedAssertion = 
+            (SAMLAssertion) stUnsignedActionResult.get(WSSecurityEngineResult.TAG_SAML_ASSERTION);
+        assertTrue(receivedAssertion != null);
+        
+        WSSecurityEngineResult signActionResult = 
+            WSSecurityUtil.fetchActionResult(results, WSConstants.SIGN);
+        assertTrue(signActionResult != null);
+        final java.util.List refs =
+            (java.util.List) signActionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
+        assertTrue(signActionResult != null && !signActionResult.isEmpty());
+        WSDataRef wsDataRef = (WSDataRef)refs.get(0);
+        String xpath = wsDataRef.getXpath();
+        assertEquals("/soapenv:Envelope/soapenv:Header/wsse:Security/Assertion", xpath);
+    }
+    
+    /**
      * Test signing a custom SOAP header with a bad localname
      */
     public void testBadLocalname() throws Exception {



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