Add processExternalEntities support to OXM

Update OXM AbstractMarshaller to support processing of external
XML entities. By default external entities will not be processed.

Issue: SPR-11376
This commit is contained in:
Rossen Stoyanchev
2014-02-18 15:48:02 -08:00
committed by Phillip Webb
parent 7efd54e243
commit edba32b309
13 changed files with 349 additions and 26 deletions

View File

@@ -162,6 +162,11 @@ public class CastorMarshaller extends AbstractMarshaller implements Initializing
this.encoding = encoding;
}
@Override
protected String getDefaultEncoding() {
return this.encoding;
}
/**
* Set the locations of the Castor XML mapping files.
*/

View File

@@ -400,6 +400,13 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi
this.processExternalEntities = processExternalEntities;
}
/**
* @return the configured value for whether XML external entities are allowed.
*/
public boolean isProcessExternalEntities() {
return this.processExternalEntities;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@ import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
@@ -149,6 +150,11 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
this.encoding = encoding;
}
@Override
protected String getDefaultEncoding() {
return this.encoding;
}
/**
* Set the document standalone flag for marshalling. By default, this flag is not present.
*/
@@ -338,7 +344,7 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
}
catch (TransformerException ex) {
throw new MarshallingFailureException(
"Could not transform to [" + ClassUtils.getShortName(result.getClass()) + "]");
"Could not transform to [" + ClassUtils.getShortName(result.getClass()) + "]", ex);
}
}
@@ -398,7 +404,7 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
@Override
protected Object unmarshalDomNode(Node node) throws XmlMappingException {
try {
return transformAndUnmarshal(new DOMSource(node));
return transformAndUnmarshal(new DOMSource(node), null);
}
catch (IOException ex) {
throw new UnmarshallingFailureException("JiBX unmarshalling exception", ex);
@@ -409,12 +415,15 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
protected Object unmarshalSaxReader(XMLReader xmlReader, InputSource inputSource)
throws XmlMappingException, IOException {
return transformAndUnmarshal(new SAXSource(xmlReader, inputSource));
return transformAndUnmarshal(new SAXSource(xmlReader, inputSource), inputSource.getEncoding());
}
private Object transformAndUnmarshal(Source source) throws IOException {
private Object transformAndUnmarshal(Source source, String encoding) throws IOException {
try {
Transformer transformer = this.transformerFactory.newTransformer();
if (encoding != null) {
transformer.setOutputProperty(OutputKeys.ENCODING, encoding);
}
ByteArrayOutputStream os = new ByteArrayOutputStream();
transformer.transform(source, new StreamResult(os));
ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
@@ -422,7 +431,7 @@ public class JibxMarshaller extends AbstractMarshaller implements InitializingBe
}
catch (TransformerException ex) {
throw new MarshallingFailureException(
"Could not transform from [" + ClassUtils.getShortName(source.getClass()) + "]");
"Could not transform from [" + ClassUtils.getShortName(source.getClass()) + "]", ex);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -73,6 +73,34 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
private final Object documentBuilderFactoryMonitor = new Object();
private boolean processExternalEntities = false;
/**
* Indicates whether external XML entities are processed when unmarshalling.
* <p>Default is {@code false}, meaning that external entities are not resolved.
* Note that processing of external entities will only be enabled/disabled when the
* {@code Source} passed to {@link #unmarshal(Source)} is a {@link SAXSource} or
* {@link StreamSource}. It has no effect for {@link DOMSource} or {@link StAXSource}
* instances.
*/
public void setProcessExternalEntities(boolean processExternalEntities) {
this.processExternalEntities = processExternalEntities;
}
/**
* @return the configured value for whether XML external entities are allowed.
*/
public boolean isProcessExternalEntities() {
return this.processExternalEntities;
}
/**
* @return the default encoding to use for marshalling or unmarshalling from
* a byte stream, or {@code null}.
*/
abstract protected String getDefaultEncoding();
/**
* Marshals the object graph with the given root into the provided {@code javax.xml.transform.Result}.
@@ -133,7 +161,7 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
return unmarshalSaxSource((SAXSource) source);
}
else if (source instanceof StreamSource) {
return unmarshalStreamSource((StreamSource) source);
return unmarshalStreamSourceNoExternalEntitities((StreamSource) source);
}
else {
throw new IllegalArgumentException("Unknown Source type: " + source.getClass());
@@ -175,7 +203,9 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
* @throws SAXException if thrown by JAXP methods
*/
protected XMLReader createXmlReader() throws SAXException {
return XMLReaderFactory.createXMLReader();
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
return xmlReader;
}
@@ -357,9 +387,43 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
return unmarshalSaxReader(saxSource.getXMLReader(), saxSource.getInputSource());
}
/**
* Template method for handling {@code StreamSource}s with protection against
* the XML External Entity (XXE) processing vulnerability taking into account
* the value of the {@link #setProcessExternalEntities(boolean)} property.
* <p>
* The default implementation wraps the StreamSource as a SAXSource and delegates
* to {@link #unmarshalSaxSource(javax.xml.transform.sax.SAXSource)}.
*
* @param streamSource the {@code StreamSource}
* @return the object graph
* @throws IOException if an I/O exception occurs
* @throws XmlMappingException if the given source cannot be mapped to an object
*
* @see <a href="https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Processing">XML_External_Entity_(XXE)_Processing</a>
*/
protected Object unmarshalStreamSourceNoExternalEntitities(StreamSource streamSource) throws XmlMappingException, IOException {
InputSource inputSource;
if (streamSource.getInputStream() != null) {
inputSource = new InputSource(streamSource.getInputStream());
inputSource.setEncoding(getDefaultEncoding());
}
else if (streamSource.getReader() != null) {
inputSource = new InputSource(streamSource.getReader());
}
else {
inputSource = new InputSource(streamSource.getSystemId());
}
return unmarshalSaxSource(new SAXSource(inputSource));
}
/**
* Template method for handling {@code StreamSource}s.
* <p>This implementation defers to {@code unmarshalInputStream} or {@code unmarshalReader}.
* <p>As of 3.2.8 and 4.0.2 this method is no longer invoked from
* {@link #unmarshal(javax.xml.transform.Source)}. The method invoked instead is
* {@link #unmarshalStreamSourceNoExternalEntitities(javax.xml.transform.stream.StreamSource)}.
*
* @param streamSource the {@code StreamSource}
* @return the object graph
* @throws IOException if an I/O exception occurs

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2012 the original author or authors.
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -113,6 +113,10 @@ public class XmlBeansMarshaller extends AbstractMarshaller {
return this.validating;
}
@Override
protected String getDefaultEncoding() {
return null;
}
/**
* This implementation returns true if the given class is an implementation of {@link XmlObject}.

View File

@@ -27,11 +27,9 @@ import java.lang.reflect.Constructor;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.XMLStreamWriter;
import javax.xml.stream.*;
import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamSource;
import com.thoughtworks.xstream.MarshallingStrategy;
import com.thoughtworks.xstream.XStream;
@@ -342,6 +340,11 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin
this.encoding = encoding;
}
@Override
protected String getDefaultEncoding() {
return this.encoding;
}
/**
* Set the classes supported by this marshaller.
* <p>If this property is empty (the default), all classes are supported.
@@ -700,6 +703,13 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin
// Unmarshalling
@Override
protected Object unmarshalStreamSourceNoExternalEntitities(StreamSource streamSource)
throws XmlMappingException, IOException {
return super.unmarshalStreamSource(streamSource);
}
@Override
protected Object unmarshalDomNode(Node node) throws XmlMappingException {
HierarchicalStreamReader streamReader;