You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wink.apache.org by ro...@apache.org on 2010/07/06 17:40:31 UTC

svn commit: r960920 - in /incubator/wink/trunk: wink-common/src/test/java/org/apache/wink/common/internal/providers/jaxb/ProvidersJAXBTest.java wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/SourceProviderTest.java

Author: rott
Date: Tue Jul  6 15:40:30 2010
New Revision: 960920

URL: http://svn.apache.org/viewvc?rev=960920&view=rev
Log:
WINK-298:  improve tests for xml security vulnerability

Modified:
    incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/providers/jaxb/ProvidersJAXBTest.java
    incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/SourceProviderTest.java

Modified: incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/providers/jaxb/ProvidersJAXBTest.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/providers/jaxb/ProvidersJAXBTest.java?rev=960920&r1=960919&r2=960920&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/providers/jaxb/ProvidersJAXBTest.java (original)
+++ incubator/wink/trunk/wink-common/src/test/java/org/apache/wink/common/internal/providers/jaxb/ProvidersJAXBTest.java Tue Jul  6 15:40:30 2010
@@ -118,6 +118,57 @@ public class ProvidersJAXBTest extends M
         "<ns2:myPojo xmlns:ns2=\"http://org/apache/wink/common/internal/providers/jaxb/jaxb1\">" +
         "<ns2:stringdata>&file;</ns2:stringdata>" +
         "</ns2:myPojo>";
+    
+    static final String xmlWithDTDEntityExpansionAttack = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
+        "<!DOCTYPE root [" +
+        "<!ENTITY % a \"x\">" +
+        "<!ENTITY % b \"%a;%a;\">" +
+        "]>" +
+        "<ns2:addNumbers xmlns:ns2=\"http://org/apache/wink/common/internal/providers/jaxb/jaxb1\">" +
+        "<ns2:arg0>&b;</ns2:arg0>" +
+        "<ns2:arg1>2</ns2:arg1>" +
+        "</ns2:addNumbers>";
+    
+    static final String xmlWithDTDEntityExpansionAttack2 = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
+        "<!DOCTYPE root [" +
+        "<!ENTITY x32 \"foobar\">" +
+        "<!ENTITY x31 \"&x32;&x32;\">" +
+        "<!ENTITY x30 \"&x31;&x31;\">" +
+        "<!ENTITY x29 \"&x30;&x30;\">" +
+        "<!ENTITY x28 \"&x29;&x29;\">" +
+        "<!ENTITY x27 \"&x28;&x28;\">" +
+        "<!ENTITY x26 \"&x27;&x27;\">" +
+        "<!ENTITY x25 \"&x26;&x26;\">" +
+        "<!ENTITY x24 \"&x25;&x25;\">" +
+        "<!ENTITY x23 \"&x24;&x24;\">" +
+        "<!ENTITY x22 \"&x23;&x23;\">" +
+        "<!ENTITY x21 \"&x22;&x22;\">" +
+        "<!ENTITY x20 \"&x21;&x21;\">" +
+        "<!ENTITY x19 \"&x20;&x20;\">" +
+        "<!ENTITY x18 \"&x19;&x19;\">" +
+        "<!ENTITY x17 \"&x18;&x18;\">" +
+        "<!ENTITY x16 \"&x17;&x17;\">" +
+        "<!ENTITY x15 \"&x16;&x16;\">" +
+        "<!ENTITY x14 \"&x15;&x15;\">" +
+        "<!ENTITY x13 \"&x14;&x14;\">" +
+        "<!ENTITY x12 \"&x13;&x13;\">" +
+        "<!ENTITY x11 \"&x12;&x12;\">" +
+        "<!ENTITY x10 \"&x11;&x11;\">" +
+        "<!ENTITY  x9 \"&x10;&x10;\">" +
+        "<!ENTITY  x8 \"&x9;&x9;\">" +
+        "<!ENTITY  x7 \"&x8;&x8;\">" +
+        "<!ENTITY  x6 \"&x7;&x7;\">" +
+        "<!ENTITY  x5 \"&x6;&x6;\">" +
+        "<!ENTITY  x4 \"&x5;&x5;\">" +
+        "<!ENTITY  x3 \"&x4;&x4;\">" +
+        "<!ENTITY  x2 \"&x3;&x3;\">" +
+        "<!ENTITY  x1 \"&x2;&x2;\">" +
+        "]>" +
+        "<ns2:addNumbers xmlns:ns2=\"http://org/apache/wink/common/internal/providers/jaxb/jaxb1\">" +
+        "<ns2:arg0>&x1;</ns2:arg0>" +
+        "<ns2:arg1>2</ns2:arg1>" +
+        "</ns2:addNumbers>";
+
 
     private WinkConfiguration winkConfiguration = null;
     private MessageBodyReader jaxbProviderReader = null;
@@ -284,5 +335,45 @@ public class ProvidersJAXBTest extends M
         MyPojo myPojo = testresponse.getValue();
         assertEquals("we could not unmarshal the test xml", "99999999", myPojo.getStringdata().trim());
     }
+    
+    @Test
+    public void testEntityExpansionAttack() throws Exception {
+        
+        final Properties props = new Properties();
+        checking(new Expectations() {{
+            allowing(winkConfiguration).getProperties(); will(returnValue(props));
+        }});
+        
+        Exception ex = null;
+        try {
+            assertTrue(jaxbProviderReader.isReadable(MyPojo.class, null, null, MediaType.TEXT_XML_TYPE));
+            ByteArrayInputStream bais = new ByteArrayInputStream(xmlWithDTDEntityExpansionAttack.getBytes());
+            Object obj = jaxbProviderReader.readFrom(MyPojo.class, null, null, MediaType.TEXT_XML_TYPE, null, bais);
+            fail("should have got an exception");
+        } catch (Exception e) {
+            ex = e;
+        }
+        assertTrue("expected an XMLStreamException", ex.getCause() instanceof XMLStreamException);
+    }
+    
+    @Test(timeout=2000)
+    public void testEntityExpansionAttack2() throws Exception {
+        
+        final Properties props = new Properties();
+        checking(new Expectations() {{
+            allowing(winkConfiguration).getProperties(); will(returnValue(props));
+        }});
+        
+        Exception ex = null;
+        try {
+            assertTrue(jaxbProviderReader.isReadable(MyPojo.class, null, null, MediaType.TEXT_XML_TYPE));
+            ByteArrayInputStream bais = new ByteArrayInputStream(xmlWithDTDEntityExpansionAttack2.getBytes());
+            Object obj = jaxbProviderReader.readFrom(MyPojo.class, null, null, MediaType.TEXT_XML_TYPE, null, bais);
+            fail("should have got an exception");
+        } catch (Exception e) {
+            ex = e;
+        }
+        assertTrue("expected an XMLStreamException", ex.getCause() instanceof XMLStreamException);
+    }
 
 }

Modified: incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/SourceProviderTest.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/SourceProviderTest.java?rev=960920&r1=960919&r2=960920&view=diff
==============================================================================
--- incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/SourceProviderTest.java (original)
+++ incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/providers/entity/SourceProviderTest.java Tue Jul  6 15:40:30 2010
@@ -59,6 +59,9 @@ import org.springframework.mock.web.Mock
 import org.springframework.mock.web.MockHttpServletResponse;
 import org.w3c.dom.Document;
 import org.xml.sax.InputSource;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLReaderFactory;
 
 public class SourceProviderTest extends MockServletInvocationTest {
 
@@ -321,6 +324,110 @@ public class SourceProviderTest extends 
         Document d = builder.parse( is );
         assertEquals("xml is bad", "YOU SHOULD NOT BE ABLE TO SEE THIS", d.getElementsByTagName("message").item(0).getTextContent().trim());
     }
+        
+    public void testDomWithDTDEntityExpansionAttack1() throws Exception {
+        
+        String classpath = System.getProperty("java.class.path");
+        StringTokenizer tokenizer = new StringTokenizer(classpath, System.getProperty("path.separator"));
+        String path = null;
+        while (tokenizer.hasMoreTokens()) {
+            path = tokenizer.nextToken();
+            if (path.endsWith("test-classes")) {
+                break;
+            }
+        }
+        
+        final String SOURCE = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
+            "<!DOCTYPE root [" +
+            "<!ENTITY % a \"x\">" +
+            "<!ENTITY % b \"%a;%a;\">" +
+            "]>" +
+            "<message>&b;</message>";
+
+        final byte[] SOURCE_BYTES = SOURCE.getBytes();
+        
+        MockHttpServletRequest request =
+            MockRequestConstructor.constructMockRequest("POST",
+                                                        "/source/domwithdtd",
+                                                        "application/xml",
+                                                        "application/xml",
+                                                        SOURCE_BYTES);
+        
+        // The SAX parser will not allow entity refs inside a DTD.  There is no special Wink code necessary for this.
+        MockHttpServletResponse response = invoke(request);
+        assertEquals(400, response.getStatus());
+        
+        // as a sanity check, let's make sure the xml is good:
+        XMLReader xmlReader = XMLReaderFactory.createXMLReader();
+        try {
+            xmlReader.parse(new InputSource(new ByteArrayInputStream(SOURCE_BYTES)));
+            fail("expected SAXParseException");
+        } catch (SAXParseException e) {
+            
+        }
+    }
+    
+    public void testDomWithDTDEntityExpansionAttack2() throws Exception {
+        
+        String classpath = System.getProperty("java.class.path");
+        StringTokenizer tokenizer = new StringTokenizer(classpath, System.getProperty("path.separator"));
+        String path = null;
+        while (tokenizer.hasMoreTokens()) {
+            path = tokenizer.nextToken();
+            if (path.endsWith("test-classes")) {
+                break;
+            }
+        }
+        
+        final String SOURCE = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>" +
+            "<!DOCTYPE root [" +
+            "<!ENTITY x32 \"foobar\">" +
+            "<!ENTITY x31 \"&x32;&x32;\">" +
+            "<!ENTITY x30 \"&x31;&x31;\">" +
+            "<!ENTITY x29 \"&x30;&x30;\">" +
+            "<!ENTITY x28 \"&x29;&x29;\">" +
+            "<!ENTITY x27 \"&x28;&x28;\">" +
+            "<!ENTITY x26 \"&x27;&x27;\">" +
+            "<!ENTITY x25 \"&x26;&x26;\">" +
+            "<!ENTITY x24 \"&x25;&x25;\">" +
+            "<!ENTITY x23 \"&x24;&x24;\">" +
+            "<!ENTITY x22 \"&x23;&x23;\">" +
+            "<!ENTITY x21 \"&x22;&x22;\">" +
+            "<!ENTITY x20 \"&x21;&x21;\">" +
+            "<!ENTITY x19 \"&x20;&x20;\">" +
+            "<!ENTITY x18 \"&x19;&x19;\">" +
+            "<!ENTITY x17 \"&x18;&x18;\">" +
+            "<!ENTITY x16 \"&x17;&x17;\">" +
+            "<!ENTITY x15 \"&x16;&x16;\">" +
+            "<!ENTITY x14 \"&x15;&x15;\">" +
+            "<!ENTITY x13 \"&x14;&x14;\">" +
+            "<!ENTITY x12 \"&x13;&x13;\">" +
+            "<!ENTITY x11 \"&x12;&x12;\">" +
+            "<!ENTITY x10 \"&x11;&x11;\">" +
+            "<!ENTITY  x9 \"&x10;&x10;\">" +
+            "<!ENTITY  x8 \"&x9;&x9;\">" +
+            "<!ENTITY  x7 \"&x8;&x8;\">" +
+            "<!ENTITY  x6 \"&x7;&x7;\">" +
+            "<!ENTITY  x5 \"&x6;&x6;\">" +
+            "<!ENTITY  x4 \"&x5;&x5;\">" +
+            "<!ENTITY  x3 \"&x4;&x4;\">" +
+            "<!ENTITY  x2 \"&x3;&x3;\">" +
+            "<!ENTITY  x1 \"&x2;&x2;\">" +
+            "]>" +
+            "<message>&x1;</message>";
+
+        final byte[] SOURCE_BYTES = SOURCE.getBytes();
+        
+        MockHttpServletRequest request =
+            MockRequestConstructor.constructMockRequest("POST",
+                                                        "/source/domwithdtd",
+                                                        "application/xml",
+                                                        "application/xml",
+                                                        SOURCE_BYTES);
+        
+        MockHttpServletResponse response = invoke(request);
+        assertEquals(400, response.getStatus());
+    }
 
     // -- Helpers