diff --git a/src/ooxml/java/org/apache/poi/ooxml/util/DocumentHelper.java b/src/ooxml/java/org/apache/poi/ooxml/util/DocumentHelper.java
index d79237d8ac..835f76e351 100644
--- a/src/ooxml/java/org/apache/poi/ooxml/util/DocumentHelper.java
+++ b/src/ooxml/java/org/apache/poi/ooxml/util/DocumentHelper.java
@@ -95,11 +95,14 @@ public final class DocumentHelper {
}
}
- private static final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ static final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
static {
documentBuilderFactory.setNamespaceAware(true);
documentBuilderFactory.setValidating(false);
+
trySetSAXFeature(documentBuilderFactory, XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ trySetSAXFeature(documentBuilderFactory, POIXMLConstants.FEATURE_LOAD_DTD_GRAMMAR, false);
+ trySetSAXFeature(documentBuilderFactory, POIXMLConstants.FEATURE_LOAD_EXTERNAL_DTD, false);
trySetXercesSecurityManager(documentBuilderFactory);
}
@@ -123,7 +126,7 @@ public final class DocumentHelper {
Object mgr = Class.forName(securityManagerClassName).newInstance();
Method setLimit = mgr.getClass().getMethod("setEntityExpansionLimit", Integer.TYPE);
setLimit.invoke(mgr, 4096);
- dbf.setAttribute("http://apache.org/xml/properties/security-manager", mgr);
+ dbf.setAttribute(POIXMLConstants.PROPERTY_SECURITY_MANAGER, mgr);
// Stop once one can be setup without error
return;
} catch (ClassNotFoundException e) {
@@ -134,7 +137,7 @@ public final class DocumentHelper {
}
// separate old version of Xerces not found => use the builtin way of setting the property
- dbf.setAttribute("http://www.oracle.com/xml/jaxp/properties/entityExpansionLimit", 4096);
+ dbf.setAttribute(POIXMLConstants.PROPERTY_ENTITY_EXPANSION_LIMIT, 4096);
}
/**
diff --git a/src/ooxml/java/org/apache/poi/ooxml/util/POIXMLConstants.java b/src/ooxml/java/org/apache/poi/ooxml/util/POIXMLConstants.java
new file mode 100644
index 0000000000..ab58e35833
--- /dev/null
+++ b/src/ooxml/java/org/apache/poi/ooxml/util/POIXMLConstants.java
@@ -0,0 +1,25 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+
+package org.apache.poi.ooxml.util;
+
+public class POIXMLConstants {
+ public static final String FEATURE_LOAD_DTD_GRAMMAR = "http://apache.org/xml/features/nonvalidating/load-dtd-grammar";
+ public static final String FEATURE_LOAD_EXTERNAL_DTD = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
+ public static final String PROPERTY_ENTITY_EXPANSION_LIMIT = "http://www.oracle.com/xml/jaxp/properties/entityExpansionLimit";
+ public static final String PROPERTY_SECURITY_MANAGER = "http://apache.org/xml/properties/security-manager";
+}
diff --git a/src/ooxml/java/org/apache/poi/ooxml/util/SAXHelper.java b/src/ooxml/java/org/apache/poi/ooxml/util/SAXHelper.java
index 806aede583..f3b1b7f6a5 100644
--- a/src/ooxml/java/org/apache/poi/ooxml/util/SAXHelper.java
+++ b/src/ooxml/java/org/apache/poi/ooxml/util/SAXHelper.java
@@ -68,6 +68,9 @@ public final class SAXHelper {
saxFactory = SAXParserFactory.newInstance();
saxFactory.setValidating(false);
saxFactory.setNamespaceAware(true);
+ trySetSAXFeature(saxFactory, XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ trySetSAXFeature(saxFactory, POIXMLConstants.FEATURE_LOAD_DTD_GRAMMAR, false);
+ trySetSAXFeature(saxFactory, POIXMLConstants.FEATURE_LOAD_EXTERNAL_DTD, false);
} catch (RuntimeException | Error re) { // NOSONAR
// this also catches NoClassDefFoundError, which may be due to a local class path issue
// This may occur if the code is run inside a web container
@@ -81,6 +84,16 @@ public final class SAXHelper {
}
}
+ private static void trySetSAXFeature(SAXParserFactory spf, String feature, boolean flag) {
+ try {
+ spf.setFeature(feature, flag);
+ } catch (Exception e) {
+ logger.log(POILogger.WARN, "SAX Feature unsupported", feature, e);
+ } catch (AbstractMethodError ame) {
+ logger.log(POILogger.WARN, "Cannot set SAX feature because outdated XML parser in classpath", feature, ame);
+ }
+ }
+
private static void trySetSAXFeature(XMLReader xmlReader, String feature) {
try {
xmlReader.setFeature(feature, true);
@@ -101,7 +114,7 @@ public final class SAXHelper {
Object mgr = Class.forName(securityManagerClassName).newInstance();
Method setLimit = mgr.getClass().getMethod("setEntityExpansionLimit", Integer.TYPE);
setLimit.invoke(mgr, 4096);
- xmlReader.setProperty("http://apache.org/xml/properties/security-manager", mgr);
+ xmlReader.setProperty(POIXMLConstants.PROPERTY_SECURITY_MANAGER, mgr);
// Stop once one can be setup without error
return;
} catch (ClassNotFoundException e) {
@@ -117,7 +130,7 @@ public final class SAXHelper {
// separate old version of Xerces not found => use the builtin way of setting the property
try {
- xmlReader.setProperty("http://www.oracle.com/xml/jaxp/properties/entityExpansionLimit", 4096);
+ xmlReader.setProperty(POIXMLConstants.PROPERTY_ENTITY_EXPANSION_LIMIT, 4096);
} catch (SAXException e) { // NOSONAR - also catch things like NoClassDefError here
// throttle the log somewhat as it can spam the log otherwise
if(System.currentTimeMillis() > lastLog + TimeUnit.MINUTES.toMillis(5)) {
diff --git a/src/ooxml/testcases/org/apache/poi/ooxml/util/TestDocumentHelper.java b/src/ooxml/testcases/org/apache/poi/ooxml/util/TestDocumentHelper.java
new file mode 100644
index 0000000000..c8147c2800
--- /dev/null
+++ b/src/ooxml/testcases/org/apache/poi/ooxml/util/TestDocumentHelper.java
@@ -0,0 +1,44 @@
+/* ====================================================================
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+==================================================================== */
+package org.apache.poi.ooxml.util;
+
+import org.junit.Test;
+import org.xml.sax.InputSource;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import java.io.ByteArrayInputStream;
+
+import static org.junit.Assert.*;
+
+public class TestDocumentHelper {
+ @Test
+ public void testDocumentBuilder() throws Exception {
+ DocumentBuilder documentBuilder = DocumentHelper.newDocumentBuilder();
+ assertNotSame(documentBuilder, DocumentHelper.newDocumentBuilder());
+ assertTrue(documentBuilder.isNamespaceAware());
+ assertFalse(documentBuilder.isValidating());
+ documentBuilder.parse(new InputSource(new ByteArrayInputStream("".getBytes("UTF-8"))));
+ }
+
+ @Test
+ public void testDocumentBuilderFactory() throws Exception {
+ assertTrue(DocumentHelper.documentBuilderFactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING));
+ assertFalse(DocumentHelper.documentBuilderFactory.getFeature(POIXMLConstants.FEATURE_LOAD_DTD_GRAMMAR));
+ assertFalse(DocumentHelper.documentBuilderFactory.getFeature(POIXMLConstants.FEATURE_LOAD_EXTERNAL_DTD));
+ }
+}
diff --git a/src/ooxml/testcases/org/apache/poi/ooxml/util/TestSAXHelper.java b/src/ooxml/testcases/org/apache/poi/ooxml/util/TestSAXHelper.java
index 825cdf40f5..4a2fa80af4 100644
--- a/src/ooxml/testcases/org/apache/poi/ooxml/util/TestSAXHelper.java
+++ b/src/ooxml/testcases/org/apache/poi/ooxml/util/TestSAXHelper.java
@@ -16,10 +16,7 @@
==================================================================== */
package org.apache.poi.ooxml.util;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNotSame;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.*;
import java.io.ByteArrayInputStream;
@@ -35,10 +32,12 @@ public class TestSAXHelper {
XMLReader reader = SAXHelper.newXMLReader();
assertNotSame(reader, SAXHelper.newXMLReader());
assertTrue(reader.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING));
+ assertFalse(reader.getFeature(POIXMLConstants.FEATURE_LOAD_DTD_GRAMMAR));
+ assertFalse(reader.getFeature(POIXMLConstants.FEATURE_LOAD_EXTERNAL_DTD));
assertEquals(SAXHelper.IGNORING_ENTITY_RESOLVER, reader.getEntityResolver());
- assertNotNull(reader.getProperty("http://www.oracle.com/xml/jaxp/properties/entityExpansionLimit"));
- assertEquals("4096", reader.getProperty("http://www.oracle.com/xml/jaxp/properties/entityExpansionLimit"));
- assertNotNull(reader.getProperty("http://apache.org/xml/properties/security-manager"));
+ assertNotNull(reader.getProperty(POIXMLConstants.PROPERTY_ENTITY_EXPANSION_LIMIT));
+ assertEquals("4096", reader.getProperty(POIXMLConstants.PROPERTY_ENTITY_EXPANSION_LIMIT));
+ assertNotNull(reader.getProperty(POIXMLConstants.PROPERTY_SECURITY_MANAGER));
reader.parse(new InputSource(new ByteArrayInputStream("".getBytes("UTF-8"))));
}