Author: giger
Date: Sun Nov 24 11:36:22 2013
New Revision: 1544959

URL: http://svn.apache.org/r1544959
Log:
WSS-484 - Streaming code can't process a Key reference pointing to an 
EncryptedData element

Modified:
    
webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/EncryptedDataInputHandler.java
    
webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/SecurityHeaderInputProcessor.java
    
webservices/wss4j/trunk/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/SignatureEncryptionTest.java

Modified: 
webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/EncryptedDataInputHandler.java
URL: 
http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/EncryptedDataInputHandler.java?rev=1544959&r1=1544958&r2=1544959&view=diff
==============================================================================
--- 
webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/EncryptedDataInputHandler.java
 (original)
+++ 
webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/EncryptedDataInputHandler.java
 Sun Nov 24 11:36:22 2013
@@ -25,19 +25,18 @@ import org.apache.wss4j.stax.ext.WSSSecu
 import org.apache.xml.security.binding.xmlenc.ReferenceList;
 import org.apache.xml.security.binding.xmlenc.ReferenceType;
 import org.apache.xml.security.exceptions.XMLSecurityException;
-import org.apache.xml.security.stax.ext.AbstractInputSecurityHeaderHandler;
-import org.apache.xml.security.stax.ext.InputProcessorChain;
-import org.apache.xml.security.stax.ext.XMLSecurityConstants;
-import org.apache.xml.security.stax.ext.XMLSecurityProperties;
+import org.apache.xml.security.stax.ext.*;
 import org.apache.xml.security.stax.ext.stax.XMLSecEvent;
 import org.apache.xml.security.stax.ext.stax.XMLSecStartElement;
 
+import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.events.Attribute;
 import java.util.Deque;
-import java.util.Iterator;
 
 /**
- * Processor for the EncryptedData XML Structure in the security header
+ * Processor for the EncryptedData XML Structure in the security header.
+ * Note, this handler is special in respect to when it is called: it is 
triggered by the
+ * EncryptedData StartElement and not when the EndElement occurs. @see 
comments in SecurityHeaderInputProcessort
  */
 public class EncryptedDataInputHandler extends 
AbstractInputSecurityHeaderHandler {
 
@@ -45,12 +44,7 @@ public class EncryptedDataInputHandler e
     public void handle(final InputProcessorChain inputProcessorChain, final 
XMLSecurityProperties securityProperties,
                        final Deque<XMLSecEvent> eventQueue, final Integer 
index) throws XMLSecurityException {
 
-        XMLSecEvent xmlSecEvent = null;
-        final Iterator<XMLSecEvent> xmlSecEventIterator = 
eventQueue.descendingIterator();
-        int curIdx = 0;
-        while (curIdx++ <= index) {
-            xmlSecEvent = xmlSecEventIterator.next();
-        }
+        XMLSecEvent xmlSecEvent = eventQueue.pollFirst();
         if (!(xmlSecEvent instanceof XMLSecStartElement)) {
             throw new 
WSSecurityException(WSSecurityException.ErrorCode.FAILURE);
         }
@@ -70,12 +64,28 @@ public class EncryptedDataInputHandler e
                                 referenceType.setURI("#" + uri);
                                 
inputProcessorChain.getSecurityContext().putAsList(WSSConstants.PROP_ENCRYPTED_DATA_REFS,
 uri);
                             }
-                            inputProcessorChain.removeProcessor(this);
                             return referenceType;
                         }
                         return null;
                     }
                 };
         inputProcessorChain.addProcessor(decryptInputProcessor);
+
+        //replay the EncryptedData event for the DecryptInputProcessor:
+        InputProcessor tmpProcessor = new 
AbstractInputProcessor(securityProperties) {
+            @Override
+            public XMLSecEvent processNextHeaderEvent(InputProcessorChain 
inputProcessorChain) throws XMLStreamException, XMLSecurityException {
+                inputProcessorChain.removeProcessor(this);
+                return encryptedDataElement;
+            }
+
+            @Override
+            public XMLSecEvent processNextEvent(InputProcessorChain 
inputProcessorChain) throws XMLStreamException, XMLSecurityException {
+                inputProcessorChain.removeProcessor(this);
+                return encryptedDataElement;
+            }
+        };
+        tmpProcessor.addBeforeProcessor(decryptInputProcessor);
+        inputProcessorChain.addProcessor(tmpProcessor);
     }
 }

Modified: 
webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/SecurityHeaderInputProcessor.java
URL: 
http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/SecurityHeaderInputProcessor.java?rev=1544959&r1=1544958&r2=1544959&view=diff
==============================================================================
--- 
webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/SecurityHeaderInputProcessor.java
 (original)
+++ 
webservices/wss4j/trunk/ws-security-stax/src/main/java/org/apache/wss4j/stax/impl/processor/input/SecurityHeaderInputProcessor.java
 Sun Nov 24 11:36:22 2013
@@ -54,7 +54,6 @@ public class SecurityHeaderInputProcesso
         org.slf4j.LoggerFactory.getLogger(SecurityHeaderInputProcessor.class);
 
     private final ArrayDeque<XMLSecEvent> xmlSecEventList = new 
ArrayDeque<XMLSecEvent>();
-    private int eventCount = 0;
     private int startIndexForProcessor = 0;
 
     public SecurityHeaderInputProcessor(WSSSecurityProperties 
securityProperties) {
@@ -85,7 +84,6 @@ public class SecurityHeaderInputProcesso
         do {
             subInputProcessorChain.reset();
             xmlSecEvent = subInputProcessorChain.processHeaderEvent();
-            eventCount++;
 
             switch (xmlSecEvent.getEventType()) {
                 case XMLStreamConstants.START_ELEMENT:
@@ -109,7 +107,15 @@ public class SecurityHeaderInputProcesso
                     } else if (documentLevel == 4 && 
responsibleSecurityHeaderFound
                             && WSSUtils.isInSecurityHeader(xmlSecStartElement,
                             ((WSSSecurityProperties) 
getSecurityProperties()).getActor())) {
-                        startIndexForProcessor = eventCount - 1;
+                        startIndexForProcessor = xmlSecEventList.size() - 1;
+
+                        //special handling for EncryptedData in the 
SecurityHeader. This way, if for example
+                        // a token was encrypted we have the possibility to 
decrypt it before so that we
+                        // are able to engage the appropriate processor for 
the token.
+                        if 
(WSSConstants.TAG_xenc_EncryptedData.equals(xmlSecStartElement.getName())) {
+                            
engageSecurityHeaderHandler(subInputProcessorChain, getSecurityProperties(),
+                                    xmlSecEventList, startIndexForProcessor, 
xmlSecStartElement.getName());
+                        }
                     }
                     break;
                 case XMLStreamConstants.END_ELEMENT:
@@ -126,9 +132,12 @@ public class SecurityHeaderInputProcesso
                             && WSSUtils.isInSecurityHeader(xmlSecEndElement,
                             ((WSSSecurityProperties) 
getSecurityProperties()).getActor())) {
                         //we are in the security header and the depth is +1, 
so every child
-                        //element should have a responsible handler:
-                        engageSecurityHeaderHandler(subInputProcessorChain, 
getSecurityProperties(),
-                                xmlSecEventList, startIndexForProcessor, 
xmlSecEndElement.getName());
+                        //element should have a responsible handler with the 
exception of an EncryptedData SecurityHeader
+                        //which is already handled in the above StartElement 
logic (@see comment above).
+                        if 
(!WSSConstants.TAG_xenc_EncryptedData.equals(xmlSecEndElement.getName())) {
+                            
engageSecurityHeaderHandler(subInputProcessorChain, getSecurityProperties(),
+                                    xmlSecEventList, startIndexForProcessor, 
xmlSecEndElement.getName());
+                        }
                         
                         // Check for multiple timestamps
                         if 
(xmlSecEndElement.getName().equals(WSSConstants.TAG_wsu_Timestamp)) {

Modified: 
webservices/wss4j/trunk/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/SignatureEncryptionTest.java
URL: 
http://svn.apache.org/viewvc/webservices/wss4j/trunk/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/SignatureEncryptionTest.java?rev=1544959&r1=1544958&r2=1544959&view=diff
==============================================================================
--- 
webservices/wss4j/trunk/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/SignatureEncryptionTest.java
 (original)
+++ 
webservices/wss4j/trunk/ws-security-stax/src/test/java/org/apache/wss4j/stax/test/SignatureEncryptionTest.java
 Sun Nov 24 11:36:22 2013
@@ -24,14 +24,24 @@ import java.io.InputStream;
 import java.security.Key;
 import java.security.NoSuchAlgorithmException;
 import java.util.ArrayList;
+import java.util.List;
 
 import javax.crypto.KeyGenerator;
 import javax.xml.namespace.QName;
 import javax.xml.stream.XMLStreamReader;
 import javax.xml.stream.XMLStreamWriter;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
 
+import org.apache.wss4j.common.WSEncryptionPart;
+import org.apache.wss4j.common.crypto.Crypto;
+import org.apache.wss4j.common.crypto.CryptoFactory;
 import org.apache.wss4j.common.ext.WSSecurityException;
+import org.apache.wss4j.dom.WSConstants;
 import org.apache.wss4j.dom.handler.WSHandlerConstants;
+import org.apache.wss4j.dom.message.WSSecEncrypt;
+import org.apache.wss4j.dom.message.WSSecHeader;
+import org.apache.wss4j.dom.message.WSSecSignature;
 import org.apache.wss4j.stax.WSSec;
 import org.apache.wss4j.stax.ext.OutboundWSSec;
 import org.apache.wss4j.stax.ext.WSSConstants;
@@ -47,7 +57,11 @@ import org.apache.xml.security.stax.impl
 import org.apache.xml.security.stax.securityEvent.SecurityEvent;
 import org.apache.xml.security.stax.securityToken.OutboundSecurityToken;
 import org.apache.xml.security.stax.securityToken.SecurityTokenProvider;
+import org.testng.Assert;
 import org.testng.annotations.Test;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
 
 public class SignatureEncryptionTest extends AbstractTestBase {
 
@@ -249,4 +263,54 @@ public class SignatureEncryptionTest ext
         }
     }
 
+    @Test
+    public void testEncryptedDataTokenSecurityHeaderWithoutReferenceInbound() 
throws Exception {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        {
+            InputStream sourceDocument = 
this.getClass().getClassLoader().getResourceAsStream("testdata/plain-soap-1.1.xml");
+
+            Document doc = 
documentBuilderFactory.newDocumentBuilder().parse(sourceDocument);
+
+            WSSecHeader secHeader = new WSSecHeader();
+            secHeader.insertSecurityHeader(doc);
+
+            WSSecSignature sign = new WSSecSignature();
+            sign.setUserInfo("transmitter", "default");
+            sign.setKeyIdentifierType(WSConstants.BST_DIRECT_REFERENCE);
+
+            Crypto crypto = 
CryptoFactory.getInstance("transmitter-crypto.properties");
+
+            sign.build(doc, crypto, secHeader);
+
+            WSSecEncrypt builder = new WSSecEncrypt();
+            builder.setKeyIdentifierType(WSConstants.THUMBPRINT_IDENTIFIER);
+            builder.setUserInfo("receiver");
+            builder.prepare(doc, crypto);
+
+            WSEncryptionPart bst = new WSEncryptionPart("BinarySecurityToken", 
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd";,
 "Element");
+            WSEncryptionPart def = new WSEncryptionPart("definitions", 
"http://schemas.xmlsoap.org/wsdl/";, "Element");
+            List<WSEncryptionPart> encryptionParts = new 
ArrayList<WSEncryptionPart>();
+            encryptionParts.add(bst);
+            encryptionParts.add(def);
+            Element ref = builder.encryptForRef(null, encryptionParts);
+            
ref.removeChild(ref.getElementsByTagNameNS("http://www.w3.org/2001/04/xmlenc#";, 
"DataReference").item(0));
+            builder.addExternalRefElement(ref, secHeader);
+            builder.prependToHeader(secHeader);
+
+            javax.xml.transform.Transformer transformer = 
TRANSFORMER_FACTORY.newTransformer();
+            transformer.transform(new DOMSource(doc), new StreamResult(baos));
+        }
+
+        //done encryption; now test decryption:
+        {
+            WSSSecurityProperties securityProperties = new 
WSSSecurityProperties();
+            
securityProperties.loadDecryptionKeystore(this.getClass().getClassLoader().getResource("receiver.jks"),
 "default".toCharArray());
+            securityProperties.setCallbackHandler(new CallbackHandlerImpl());
+            Document document = doInboundSecurity(securityProperties, 
xmlInputFactory.createXMLStreamReader(new 
ByteArrayInputStream(baos.toByteArray())));
+
+            //no encrypted content
+            NodeList nodeList = 
document.getElementsByTagNameNS(WSSConstants.TAG_xenc_EncryptedData.getNamespaceURI(),
 WSSConstants.TAG_xenc_EncryptedData.getLocalPart());
+            Assert.assertEquals(nodeList.getLength(), 0);
+        }
+    }
 }


Reply via email to