Skip to content

Commit

Permalink
CAMEL-8312: XML External Entity (XXE) injection in XPath. Thanks to S…
Browse files Browse the repository at this point in the history
…tephan Siano for the patch.
  • Loading branch information
davsclaus committed Mar 2, 2015
1 parent 3f0e220 commit 7360aad
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 35 deletions.
Expand Up @@ -18,7 +18,6 @@

import java.io.File;
import java.io.InputStream;
import java.io.StringReader;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
Expand Down Expand Up @@ -51,7 +50,6 @@
import org.apache.camel.Predicate;
import org.apache.camel.RuntimeExpressionException;
import org.apache.camel.WrappedFile;
import org.apache.camel.component.bean.BeanInvocation;
import org.apache.camel.impl.DefaultExchange;
import org.apache.camel.spi.Language;
import org.apache.camel.spi.NamespaceAware;
Expand Down Expand Up @@ -1116,25 +1114,6 @@ protected Object doGetDocument(Exchange exchange, Object body) throws Exception
}
}

// okay we can try to remedy the failed conversion by some special types
if (answer == null) {
// let's try coercing some common types into something JAXP work with the best for special types
if (body instanceof WrappedFile) {
// special for files so we can work with them out of the box
InputStream is = exchange.getContext().getTypeConverter().convertTo(InputStream.class, exchange, body);
answer = new InputSource(is);
} else if (body instanceof BeanInvocation) {
// if its a null bean invocation then handle that specially
BeanInvocation bi = exchange.getContext().getTypeConverter().convertTo(BeanInvocation.class, exchange, body);
if (bi.getArgs() != null && bi.getArgs().length == 1 && bi.getArgs()[0] == null) {
// its a null argument from the bean invocation so use null as answer
answer = null;
}
} else if (body instanceof String) {
answer = new InputSource(new StringReader((String) body));
}
}

if (type == null && answer == null) {
// fallback to get the body as is
answer = body;
Expand Down
Expand Up @@ -19,11 +19,13 @@

import java.io.FileNotFoundException;

import javax.xml.xpath.XPathExpressionException;

import org.apache.camel.ContextTestSupport;
import org.apache.camel.Exchange;
import org.apache.camel.NoTypeConversionAvailableException;
import org.apache.camel.RuntimeCamelException;
import org.apache.camel.TypeConversionException;
import org.apache.camel.converter.jaxp.XmlConverter;
import org.xml.sax.SAXParseException;

import static org.apache.camel.builder.xml.XPathBuilder.xpath;

Expand All @@ -32,18 +34,19 @@ public class XPathFeatureTest extends ContextTestSupport {

public static final String XML_DATA = " <!DOCTYPE foo [ "
+ " <!ELEMENT foo ANY > <!ENTITY xxe SYSTEM \"file:///bin/test.sh\" >]> <test> &xxe; </test>";


public static final String XML_DATA_INVALID = " <!DOCTYPE foo [ "
+ " <!ELEMENT foo ANY > <!ENTITY xxe SYSTEM \"file:///bin/test.sh\" >]> <test> &xxe; </test><notwellformed>";

@Override
public boolean isUseRouteBuilder() {
return false;
}

public void testXPathResult() throws Exception {
String result = (String)xpath("/").stringResult().evaluate(createExchange(XML_DATA));
assertEquals("Get a wrong result", " ", result);
}

public void testXPath() throws Exception {

// Set this feature will enable the external general entities
Expand All @@ -52,16 +55,35 @@ public void testXPath() throws Exception {
try {
xpath("/").stringResult().evaluate(createExchange(XML_DATA));
fail("Expect an Exception here");
} catch (Exception ex) {
assertTrue("Get a wrong exception cause.", ex instanceof InvalidXPathExpression);
assertTrue("Get a wrong exception cause.", ex.getCause() instanceof XPathExpressionException);
} catch (TypeConversionException ex) {
assertTrue("Get a wrong exception cause.", ex.getCause() instanceof RuntimeCamelException);
assertTrue("Get a wrong exception cause.", ex.getCause().getCause() instanceof FileNotFoundException);
} finally {
System.clearProperty(DOM_BUILER_FACTORY_FEATRUE + ":"
+ "http://xml.org/sax/features/external-general-entities");
}
}


public void testXPathNoTypeConverter() throws Exception {
try {
// define a class without type converter as document type
xpath("/").documentType(Exchange.class).stringResult().evaluate(createExchange(XML_DATA));
fail("Expect an Exception here");
} catch (RuntimeCamelException ex) {
assertTrue("Get a wrong exception cause.", ex.getCause() instanceof NoTypeConversionAvailableException);
}
}

public void testXPathResultOnInvalidData() throws Exception {
try {
xpath("/").stringResult().evaluate(createExchange(XML_DATA_INVALID));
fail("Expect an Exception here");
} catch (TypeConversionException ex) {
assertTrue("Get a wrong exception cause.", ex.getCause() instanceof RuntimeCamelException);
assertTrue("Get a wrong exception cause.", ex.getCause().getCause() instanceof SAXParseException);
}
}

protected Exchange createExchange(Object xml) {
Exchange exchange = createExchangeWithBody(context, xml);
return exchange;
Expand Down
Expand Up @@ -61,19 +61,22 @@ private void sendEntityMessage(Object message) throws Exception {
Exchange exchange = list.get(0);
String xml = exchange.getIn().getBody(String.class);
assertTrue("Get a wrong transformed message", xml.indexOf("<transformed subject=\"\">") > 0);



endpoint.reset();
endpoint.expectedMessageCount(1);

try {
template.sendBody("direct:start2", message);
fail("Expect an exception here");
list = endpoint.getReceivedExchanges();
exchange = list.get(0);
xml = exchange.getIn().getBody(String.class);
assertTrue("Get a wrong transformed message", xml.indexOf("<transformed subject=\"\">") > 0);
} catch (Exception ex) {
// expect an exception here
assertTrue("Get a wrong exception", ex instanceof CamelExecutionException);
// the file could not be found
assertTrue("Get a wrong exception cause", ex.getCause() instanceof TransformerException);
}

}


Expand Down

0 comments on commit 7360aad

Please sign in to comment.