Skip to content

Commit 44ee51a

Browse files
committed
Disable URL resolution in DTD declarations
Issue: SPR-11768
1 parent ba6d187 commit 44ee51a

File tree

7 files changed

+88
-8
lines changed

7 files changed

+88
-8
lines changed

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

Lines changed: 14 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;
@@ -72,6 +73,7 @@
7273
import org.apache.commons.logging.Log;
7374
import org.apache.commons.logging.LogFactory;
7475
import org.w3c.dom.ls.LSResourceResolver;
76+
import org.xml.sax.EntityResolver;
7577
import org.xml.sax.InputSource;
7678
import org.xml.sax.SAXException;
7779
import org.xml.sax.XMLReader;
@@ -806,7 +808,11 @@ else if (streamSource.getReader() != null) {
806808
if (xmlReader == null) {
807809
xmlReader = XMLReaderFactory.createXMLReader();
808810
}
809-
xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
811+
String name = "http://xml.org/sax/features/external-general-entities";
812+
xmlReader.setFeature(name, isProcessExternalEntities());
813+
if (!isProcessExternalEntities()) {
814+
xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
815+
}
810816
return new SAXSource(xmlReader, inputSource);
811817
}
812818
catch (SAXException ex) {
@@ -1019,4 +1025,11 @@ public String getName() {
10191025
}
10201026
}
10211027

1028+
private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
1029+
@Override
1030+
public InputSource resolveEntity(String publicId, String systemId) {
1031+
return new InputSource(new StringReader(""));
1032+
}
1033+
};
1034+
10221035
}

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;
@@ -43,6 +44,7 @@
4344
import org.w3c.dom.Document;
4445
import org.w3c.dom.Node;
4546
import org.xml.sax.ContentHandler;
47+
import org.xml.sax.EntityResolver;
4648
import org.xml.sax.InputSource;
4749
import org.xml.sax.SAXException;
4850
import org.xml.sax.XMLReader;
@@ -156,6 +158,9 @@ protected DocumentBuilder createDocumentBuilder(DocumentBuilderFactory factory)
156158
protected XMLReader createXmlReader() throws SAXException {
157159
XMLReader xmlReader = XMLReaderFactory.createXMLReader();
158160
xmlReader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
161+
if (!isProcessExternalEntities()) {
162+
xmlReader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
163+
}
159164
return xmlReader;
160165
}
161166

@@ -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;
@@ -230,7 +232,16 @@ protected void writeToResult(T t, HttpHeaders headers, Result result) throws IOE
230232
protected XMLInputFactory createXmlInputFactory() {
231233
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
232234
inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
235+
inputFactory.setXMLResolver(NO_OP_XML_RESOLVER);
233236
return inputFactory;
234237
}
235238

239+
240+
private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() {
241+
@Override
242+
public Object resolveEntity(String publicID, String systemID, String base, String ns) {
243+
return new ByteArrayInputStream(new byte[0]);
244+
}
245+
};
246+
236247
}

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;
@@ -67,6 +69,10 @@ public void setProcessExternalEntities(boolean processExternalEntities) {
6769
this.processExternalEntities = processExternalEntities;
6870
}
6971

72+
public boolean isProcessExternalEntities() {
73+
return this.processExternalEntities;
74+
}
75+
7076
@Override
7177
public boolean canRead(Class<?> clazz, MediaType mediaType) {
7278
return (clazz.isAnnotationPresent(XmlRootElement.class) || clazz.isAnnotationPresent(XmlType.class)) &&
@@ -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: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@
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;
2829
import javax.xml.stream.XMLInputFactory;
30+
import javax.xml.stream.XMLResolver;
2931
import javax.xml.stream.XMLStreamException;
3032
import javax.xml.stream.XMLStreamReader;
3133
import javax.xml.transform.Result;
@@ -39,6 +41,7 @@
3941
import javax.xml.transform.stream.StreamSource;
4042

4143
import org.w3c.dom.Document;
44+
import org.xml.sax.EntityResolver;
4245
import org.xml.sax.InputSource;
4346
import org.xml.sax.SAXException;
4447
import org.xml.sax.XMLReader;
@@ -136,8 +139,11 @@ private DOMSource readDOMSource(InputStream body) throws IOException {
136139
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
137140
documentBuilderFactory.setNamespaceAware(true);
138141
documentBuilderFactory.setFeature(
139-
"http://xml.org/sax/features/external-general-entities", this.processExternalEntities);
142+
"http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
140143
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
144+
if (!isProcessExternalEntities()) {
145+
documentBuilder.setEntityResolver(NO_OP_ENTITY_RESOLVER);
146+
}
141147
Document document = documentBuilder.parse(body);
142148
return new DOMSource(document);
143149
}
@@ -152,9 +158,11 @@ private DOMSource readDOMSource(InputStream body) throws IOException {
152158
private SAXSource readSAXSource(InputStream body) throws IOException {
153159
try {
154160
XMLReader reader = XMLReaderFactory.createXMLReader();
155-
reader.setFeature(
156-
"http://xml.org/sax/features/external-general-entities", this.processExternalEntities);
161+
reader.setFeature("http://xml.org/sax/features/external-general-entities", isProcessExternalEntities());
157162
byte[] bytes = StreamUtils.copyToByteArray(body);
163+
if (!isProcessExternalEntities()) {
164+
reader.setEntityResolver(NO_OP_ENTITY_RESOLVER);
165+
}
158166
return new SAXSource(reader, new InputSource(new ByteArrayInputStream(bytes)));
159167
}
160168
catch (SAXException ex) {
@@ -165,7 +173,10 @@ private SAXSource readSAXSource(InputStream body) throws IOException {
165173
private Source readStAXSource(InputStream body) {
166174
try {
167175
XMLInputFactory inputFactory = XMLInputFactory.newFactory();
168-
inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, this.processExternalEntities);
176+
inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, isProcessExternalEntities());
177+
if (!isProcessExternalEntities()) {
178+
inputFactory.setXMLResolver(NO_OP_XML_RESOLVER);
179+
}
169180
XMLStreamReader streamReader = inputFactory.createXMLStreamReader(body);
170181
return new StAXSource(streamReader);
171182
}
@@ -231,4 +242,19 @@ public void write(byte[] b, int off, int len) throws IOException {
231242
}
232243
}
233244

245+
246+
private static final EntityResolver NO_OP_ENTITY_RESOLVER = new EntityResolver() {
247+
@Override
248+
public InputSource resolveEntity(String publicId, String systemId) {
249+
return new InputSource(new StringReader(""));
250+
}
251+
};
252+
253+
private static final XMLResolver NO_OP_XML_RESOLVER = new XMLResolver() {
254+
@Override
255+
public Object resolveEntity(String publicID, String systemID, String base, String ns) {
256+
return new ByteArrayInputStream(new byte[0]);
257+
}
258+
};
259+
234260
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public void readXmlType() throws Exception {
110110
@Test
111111
public void readXmlRootElementExternalEntityDisabled() throws Exception {
112112
Resource external = new ClassPathResource("external.txt", getClass());
113-
String content = "<!DOCTYPE root [" +
113+
String content = "<!DOCTYPE root SYSTEM \"http://192.168.28.42/1.jsp\" [" +
114114
" <!ELEMENT external ANY >\n" +
115115
" <!ENTITY ext SYSTEM \"" + external.getURI() + "\" >]>" +
116116
" <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
@@ -66,7 +66,7 @@ public void setUp() throws IOException {
6666
converter = new SourceHttpMessageConverter<Source>();
6767
Resource external = new ClassPathResource("external.txt", getClass());
6868

69-
bodyExternal = "<!DOCTYPE root [" +
69+
bodyExternal = "<!DOCTYPE root SYSTEM \"http://192.168.28.42/1.jsp\" [" +
7070
" <!ELEMENT root ANY >\n" +
7171
" <!ENTITY ext SYSTEM \"" + external.getURI() + "\" >]><root>&ext;</root>";
7272
}

0 commit comments

Comments
 (0)