Skip to content

Commit c6503eb

Browse files
committed
Disable URL resolution in DTD declarations
Issue: SPR-11768
1 parent f42f223 commit c6503eb

File tree

7 files changed

+85
-6
lines changed

7 files changed

+85
-6
lines changed

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.io.IOException;
2222
import java.io.InputStream;
2323
import java.io.OutputStream;
24+
import java.io.StringReader;
2425
import java.io.UnsupportedEncodingException;
2526
import java.lang.reflect.GenericArrayType;
2627
import java.lang.reflect.ParameterizedType;
@@ -70,6 +71,7 @@
7071
import org.apache.commons.logging.Log;
7172
import org.apache.commons.logging.LogFactory;
7273
import org.w3c.dom.ls.LSResourceResolver;
74+
import org.xml.sax.EntityResolver;
7375
import org.xml.sax.InputSource;
7476
import org.xml.sax.SAXException;
7577
import org.xml.sax.XMLReader;
@@ -800,7 +802,11 @@ else if (streamSource.getReader() != null) {
800802
if (xmlReader == null) {
801803
xmlReader = XMLReaderFactory.createXMLReader();
802804
}
803-
xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
805+
String name = "http://xml.org/sax/features/external-general-entities";
806+
xmlReader.setFeature(name, isProcessExternalEntities());
807+
if (!isProcessExternalEntities()) {
808+
xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
809+
}
804810
return new SAXSource(xmlReader, inputSource);
805811
}
806812
catch (SAXException ex) {
@@ -1009,4 +1015,12 @@ public String getName() {
10091015
}
10101016
}
10111017

1018+
1019+
private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
1020+
@Override
1021+
public InputSource resolveEntity(String publicId, String systemId) {
1022+
return new InputSource(new StringReader(""));
1023+
}
1024+
};
1025+
10121026
}

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import java.io.InputStream;
2121
import java.io.OutputStream;
2222
import java.io.Reader;
23+
import java.io.StringReader;
2324
import java.io.Writer;
2425
import javax.xml.parsers.DocumentBuilder;
2526
import javax.xml.parsers.DocumentBuilderFactory;
@@ -42,6 +43,7 @@
4243
import org.apache.commons.logging.LogFactory;
4344
import org.w3c.dom.Node;
4445
import org.xml.sax.ContentHandler;
46+
import org.xml.sax.EntityResolver;
4547
import org.xml.sax.InputSource;
4648
import org.xml.sax.SAXException;
4749
import org.xml.sax.XMLReader;
@@ -134,6 +136,9 @@ protected DocumentBuilder createDocumentBuilder(DocumentBuilderFactory factory)
134136
protected XMLReader createXmlReader() throws SAXException {
135137
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
136138
xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
139+
if (!isProcessExternalEntities()) {
140+
xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
141+
}
137142
return xmlReader;
138143
}
139144

@@ -545,4 +550,12 @@ protected abstract Object unmarshalInputStream(InputStream inputStream)
545550
protected abstract Object unmarshalReader(Reader reader)
546551
throws XmlMappingException, IOException;
547552

553+
554+
private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
555+
@Override
556+
public InputSource resolveEntity(String publicId, String systemId) {
557+
return new InputSource(new StringReader(""));
558+
}
559+
};
560+
548561
}

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.http.converter.xml;
1818

19+
import java.io.ByteArrayInputStream;
1920
import java.io.IOException;
2021
import java.lang.reflect.ParameterizedType;
2122
import java.lang.reflect.Type;
@@ -32,6 +33,7 @@
3233
import javax.xml.bind.annotation.XmlRootElement;
3334
import javax.xml.bind.annotation.XmlType;
3435
import javax.xml.stream.XMLInputFactory;
36+
import javax.xml.stream.XMLResolver;
3537
import javax.xml.stream.XMLStreamException;
3638
import javax.xml.stream.XMLStreamReader;
3739
import javax.xml.transform.Result;
@@ -226,7 +228,16 @@ protected void writeToResult(T t, HttpHeaders headers, Result result) throws IOE
226228
protected XMLInputFactory createXmlInputFactory() {
227229
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
228230
inputFactory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false);
231+
inputFactory.setXMLResolver(NO_OP_XML_RESOLVER);
229232
return inputFactory;
230233
}
231234

235+
236+
private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() {
237+
@Override
238+
public Object resolveEntity(String publicID, String systemID, String base, String ns) {
239+
return new ByteArrayInputStream(new byte[0]);
240+
}
241+
};
242+
232243
}

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

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.springframework.http.converter.xml;
1818

1919
import java.io.IOException;
20+
import java.io.StringReader;
2021
import javax.xml.bind.JAXBElement;
2122
import javax.xml.bind.JAXBException;
2223
import javax.xml.bind.MarshalException;
@@ -38,6 +39,7 @@
3839
import org.springframework.http.converter.HttpMessageNotReadableException;
3940
import org.springframework.http.converter.HttpMessageNotWritableException;
4041
import org.springframework.util.ClassUtils;
42+
import org.xml.sax.EntityResolver;
4143
import org.xml.sax.InputSource;
4244
import org.xml.sax.SAXException;
4345
import org.xml.sax.XMLReader;
@@ -66,6 +68,10 @@ public void setProcessExternalEntities(boolean processExternalEntities) {
6668
this.processExternalEntities = processExternalEntities;
6769
}
6870

71+
public boolean isProcessExternalEntities() {
72+
return this.processExternalEntities;
73+
}
74+
6975

7076
@Override
7177
public boolean canRead(Class<?> clazz, MediaType mediaType) {
@@ -113,7 +119,10 @@ protected Source processSource(Source source) {
113119
try {
114120
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
115121
String featureName = "http://xml.org/sax/features/external-general-entities";
116-
xmlReader.setFeature(featureName, this.processExternalEntities);
122+
xmlReader.setFeature(featureName, isProcessExternalEntities());
123+
if (!isProcessExternalEntities()) {
124+
xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
125+
}
117126
return new SAXSource(xmlReader, inputSource);
118127
}
119128
catch (SAXException ex) {
@@ -148,4 +157,12 @@ private void setCharset(MediaType contentType, Marshaller marshaller) throws Pro
148157
}
149158
}
150159

160+
161+
private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
162+
@Override
163+
public InputSource resolveEntity(String publicId, String systemId) {
164+
return new InputSource(new StringReader(""));
165+
}
166+
};
167+
151168
}

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

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@
2020
import java.io.IOException;
2121
import java.io.InputStream;
2222
import java.io.OutputStream;
23+
import java.io.StringReader;
2324
import java.util.HashSet;
2425
import java.util.Set;
2526
import javax.xml.parsers.DocumentBuilder;
2627
import javax.xml.parsers.DocumentBuilderFactory;
2728
import javax.xml.parsers.ParserConfigurationException;
29+
import javax.xml.stream.XMLResolver;
2830
import javax.xml.transform.Result;
2931
import javax.xml.transform.Source;
3032
import javax.xml.transform.TransformerException;
@@ -35,6 +37,7 @@
3537
import javax.xml.transform.stream.StreamSource;
3638

3739
import org.w3c.dom.Document;
40+
import org.xml.sax.EntityResolver;
3841
import org.xml.sax.InputSource;
3942
import org.xml.sax.SAXException;
4043
import org.xml.sax.XMLReader;
@@ -128,8 +131,11 @@ private DOMSource readDOMSource(InputStream body) throws IOException {
128131
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
129132
documentBuilderFactory.setNamespaceAware(true);
130133
documentBuilderFactory.setFeature(
131-
"http://xml.org/sax/features/external-general-entities", this.processExternalEntities);
134+
"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
132135
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
136+
if (!isProcessExternalEntities()) {
137+
documentBuilder.setEntityResolver(NO_OP_ENTITY_RESOLVER);
138+
}
133139
Document document = documentBuilder.parse(body);
134140
return new DOMSource(document);
135141
}
@@ -145,8 +151,11 @@ private SAXSource readSAXSource(InputStream body) throws IOException {
145151
try {
146152
XMLReader reader = XMLReaderFactory.createXMLReader();
147153
reader.setFeature(
148-
"http://xml.org/sax/features/external-general-entities", this.processExternalEntities);
154+
"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
149155
byte[] bytes = StreamUtils.copyToByteArray(body);
156+
if (!isProcessExternalEntities()) {
157+
reader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
158+
}
150159
return new SAXSource(reader, new InputSource(new ByteArrayInputStream(bytes)));
151160
}
152161
catch (SAXException ex) {
@@ -211,4 +220,19 @@ public void write(byte[] b, int off, int len) throws IOException {
211220
}
212221
}
213222

223+
224+
private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
225+
@Override
226+
public InputSource resolveEntity(String publicId, String systemId) {
227+
return new InputSource(new StringReader(""));
228+
}
229+
};
230+
231+
private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() {
232+
@Override
233+
public Object resolveEntity(String publicID, String systemID, String base, String ns) {
234+
return new ByteArrayInputStream(new byte[0]);
235+
}
236+
};
237+
214238
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ public void readXmlType() throws Exception {
100100
@Test
101101
public void readXmlRootElementExternalEntityDisabled() throws Exception {
102102
Resource external = new ClassPathResource("external.txt", getClass());
103-
String content = "<!DOCTYPE root [" +
103+
String content = "<!DOCTYPE root SYSTEM \"http://192.168.28.42/1.jsp\" [" +
104104
" <!ELEMENT external ANY >\n" +
105105
" <!ENTITY ext SYSTEM \"" + external.getURI() + "\" >]>" +
106106
" <rootElement><external>&ext;</external></rootElement>";

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ public class SourceHttpMessageConverterTests {
6363
public void setUp() throws IOException {
6464
converter = new SourceHttpMessageConverter<Source>();
6565
Resource external = new ClassPathResource("external.txt", getClass());
66-
bodyExternal = "<!DOCTYPE root [" +
66+
bodyExternal = "<!DOCTYPE root SYSTEM \"http://192.168.28.42/1.jsp\" [" +
6767
" <!ELEMENT root ANY >\n" +
6868
" <!ENTITY ext SYSTEM \"" + external.getURI() + "\" >]><root>&ext;</root>";
6969
}

0 commit comments

Comments
 (0)