Browse Source

Disable URL resolution in DTD declarations

Issue: SPR-11768
pull/493/merge
Rossen Stoyanchev 12 years ago
parent
commit
8e096aeef5
  1. 15
      spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java
  2. 13
      spring-oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java
  3. 11
      spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverter.java
  4. 19
      spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java
  5. 34
      spring-web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java
  6. 2
      spring-web/src/test/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverterTests.java
  7. 2
      spring-web/src/test/java/org/springframework/http/converter/xml/SourceHttpMessageConverterTests.java

15
spring-oxm/src/main/java/org/springframework/oxm/jaxb/Jaxb2Marshaller.java

@ -21,6 +21,7 @@ import java.io.ByteArrayInputStream; @@ -21,6 +21,7 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
@ -72,6 +73,7 @@ import javax.xml.validation.SchemaFactory; @@ -72,6 +73,7 @@ import javax.xml.validation.SchemaFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.ls.LSResourceResolver;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
@ -806,7 +808,11 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi @@ -806,7 +808,11 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi
if (xmlReader == null) {
xmlReader = XMLReaderFactory.createXMLReader();
}
xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
String name = "http://xml.org/sax/features/external-general-entities";
xmlReader.setFeature(name, isProcessExternalEntities());
if (!isProcessExternalEntities()) {
xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
}
return new SAXSource(xmlReader, inputSource);
}
catch (SAXException ex) {
@ -1019,4 +1025,11 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi @@ -1019,4 +1025,11 @@ public class Jaxb2Marshaller implements MimeMarshaller, MimeUnmarshaller, Generi
}
}
private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
@Override
public InputSource resolveEntity(String publicId, String systemId) {
return new InputSource(new StringReader(""));
}
};
}

13
spring-oxm/src/main/java/org/springframework/oxm/support/AbstractMarshaller.java

@ -20,6 +20,7 @@ import java.io.IOException; @@ -20,6 +20,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.io.Writer;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@ -43,6 +44,7 @@ import org.apache.commons.logging.LogFactory; @@ -43,6 +44,7 @@ import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.ContentHandler;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
@ -156,6 +158,9 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { @@ -156,6 +158,9 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
protected XMLReader createXmlReader() throws SAXException {
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
if (!isProcessExternalEntities()) {
xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
}
return xmlReader;
}
@ -545,4 +550,12 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller { @@ -545,4 +550,12 @@ public abstract class AbstractMarshaller implements Marshaller, Unmarshaller {
protected abstract Object unmarshalReader(Reader reader)
throws XmlMappingException, IOException;
private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
@Override
public InputSource resolveEntity(String publicId, String systemId) {
return new InputSource(new StringReader(""));
}
};
}

11
spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2CollectionHttpMessageConverter.java

@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
package org.springframework.http.converter.xml;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
@ -32,6 +33,7 @@ import javax.xml.bind.Unmarshaller; @@ -32,6 +33,7 @@ import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLResolver;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Result;
@ -230,7 +232,16 @@ public class Jaxb2CollectionHttpMessageConverter<T extends Collection> @@ -230,7 +232,16 @@ public class Jaxb2CollectionHttpMessageConverter<T extends Collection>
protected XMLInputFactory createXmlInputFactory() {
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
inputFactory.setXMLResolver(NO_OP_XML_RESOLVER);
return inputFactory;
}
private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() {
@Override
public Object resolveEntity(String publicID, String systemID, String base, String ns) {
return new ByteArrayInputStream(new byte[0]);
}
};
}

19
spring-web/src/main/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverter.java

@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
package org.springframework.http.converter.xml;
import java.io.IOException;
import java.io.StringReader;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.MarshalException;
@ -38,6 +39,7 @@ import org.springframework.http.converter.HttpMessageConversionException; @@ -38,6 +39,7 @@ import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.util.ClassUtils;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
@ -67,6 +69,10 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa @@ -67,6 +69,10 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa
this.processExternalEntities = processExternalEntities;
}
public boolean isProcessExternalEntities() {
return this.processExternalEntities;
}
@Override
public boolean canRead(Class<?> clazz, MediaType mediaType) {
return (clazz.isAnnotationPresent(XmlRootElement.class) || clazz.isAnnotationPresent(XmlType.class)) &&
@ -113,7 +119,10 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa @@ -113,7 +119,10 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa
try {
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
String featureName = "http://xml.org/sax/features/external-general-entities";
xmlReader.setFeature(featureName, this.processExternalEntities);
xmlReader.setFeature(featureName, isProcessExternalEntities());
if (!isProcessExternalEntities()) {
xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
}
return new SAXSource(xmlReader, inputSource);
}
catch (SAXException ex) {
@ -148,4 +157,12 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa @@ -148,4 +157,12 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa
}
}
private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
@Override
public InputSource resolveEntity(String publicId, String systemId) {
return new InputSource(new StringReader(""));
}
};
}

34
spring-web/src/main/java/org/springframework/http/converter/xml/SourceHttpMessageConverter.java

@ -20,12 +20,14 @@ import java.io.ByteArrayInputStream; @@ -20,12 +20,14 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.util.HashSet;
import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLResolver;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Result;
@ -39,6 +41,7 @@ import javax.xml.transform.stream.StreamResult; @@ -39,6 +41,7 @@ import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import org.w3c.dom.Document;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
@ -136,8 +139,11 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe @@ -136,8 +139,11 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
documentBuilderFactory.setFeature(
"http://xml.org/sax/features/external-general-entities", this.processExternalEntities);
"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
if (!isProcessExternalEntities()) {
documentBuilder.setEntityResolver(NO_OP_ENTITY_RESOLVER);
}
Document document = documentBuilder.parse(body);
return new DOMSource(document);
}
@ -152,9 +158,11 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe @@ -152,9 +158,11 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe
private SAXSource readSAXSource(InputStream body) throws IOException {
try {
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setFeature(
"http://xml.org/sax/features/external-general-entities", this.processExternalEntities);
reader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
byte[] bytes = StreamUtils.copyToByteArray(body);
if (!isProcessExternalEntities()) {
reader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
}
return new SAXSource(reader, new InputSource(new ByteArrayInputStream(bytes)));
}
catch (SAXException ex) {
@ -165,7 +173,10 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe @@ -165,7 +173,10 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe
private Source readStAXSource(InputStream body) {
try {
XMLInputFactory inputFactory = XMLInputFactory.newFactory();
inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, this.processExternalEntities);
inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, isProcessExternalEntities());
if (!isProcessExternalEntities()) {
inputFactory.setXMLResolver(NO_OP_XML_RESOLVER);
}
XMLStreamReader streamReader = inputFactory.createXMLStreamReader(body);
return new StAXSource(streamReader);
}
@ -231,4 +242,19 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe @@ -231,4 +242,19 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractHttpMe
}
}
private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
@Override
public InputSource resolveEntity(String publicId, String systemId) {
return new InputSource(new StringReader(""));
}
};
private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() {
@Override
public Object resolveEntity(String publicID, String systemID, String base, String ns) {
return new ByteArrayInputStream(new byte[0]);
}
};
}

2
spring-web/src/test/java/org/springframework/http/converter/xml/Jaxb2RootElementHttpMessageConverterTests.java

@ -110,7 +110,7 @@ public class Jaxb2RootElementHttpMessageConverterTests { @@ -110,7 +110,7 @@ public class Jaxb2RootElementHttpMessageConverterTests {
@Test
public void readXmlRootElementExternalEntityDisabled() throws Exception {
Resource external = new ClassPathResource("external.txt", getClass());
String content = "<!DOCTYPE root [" +
String content = "<!DOCTYPE root SYSTEM \"http://192.168.28.42/1.jsp\" [" +
" <!ELEMENT external ANY >\n" +
" <!ENTITY ext SYSTEM \"" + external.getURI() + "\" >]>" +
" <rootElement><external>&ext;</external></rootElement>";

2
spring-web/src/test/java/org/springframework/http/converter/xml/SourceHttpMessageConverterTests.java

@ -66,7 +66,7 @@ public class SourceHttpMessageConverterTests { @@ -66,7 +66,7 @@ public class SourceHttpMessageConverterTests {
converter = new SourceHttpMessageConverter<Source>();
Resource external = new ClassPathResource("external.txt", getClass());
bodyExternal = "<!DOCTYPE root [" +
bodyExternal = "<!DOCTYPE root SYSTEM \"http://192.168.28.42/1.jsp\" [" +
" <!ELEMENT root ANY >\n" +
" <!ENTITY ext SYSTEM \"" + external.getURI() + "\" >]><root>&ext;</root>";
}

Loading…
Cancel
Save