This is an automated email from the ASF dual-hosted git repository.
tballison pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tika.git
The following commit(s) were added to refs/heads/main by this push:
new 6620738735 [TIKA-4935] Delegate JAXP parser configuration to Apache
Commons Secure (#3262)
6620738735 is described below
commit 6620738735af7c7fdf36495551d489c13344a51e
Author: Gary Gregory <[email protected]>
AuthorDate: Mon Sep 28 10:46:53 2026 -0400
[TIKA-4935] Delegate JAXP parser configuration to Apache Commons Secure
(#3262)
---
.../java/org/apache/tika/utils/XMLReaderUtils.java | 6 +-
.../org/apache/tika/utils/XMLReaderUtilsTest.java | 73 ++++++++++++++++++++++
2 files changed, 74 insertions(+), 5 deletions(-)
diff --git a/tika-core/src/main/java/org/apache/tika/utils/XMLReaderUtils.java
b/tika-core/src/main/java/org/apache/tika/utils/XMLReaderUtils.java
index f519481358..62a27eda5f 100644
--- a/tika-core/src/main/java/org/apache/tika/utils/XMLReaderUtils.java
+++ b/tika-core/src/main/java/org/apache/tika/utils/XMLReaderUtils.java
@@ -290,12 +290,8 @@ public class XMLReaderUtils implements Serializable {
LOG.debug("XMLInputFactory class {}", factory.getClass());
}
- tryToSetStaxProperty(factory, XMLInputFactory.IS_NAMESPACE_AWARE,
true);
-
- //try to configure secure processing
- tryToSetStaxProperty(factory, XMLInputFactory.IS_VALIDATING, false);
+ //try to cause DTDs to throw exceptions
tryToSetStaxProperty(factory, XMLInputFactory.SUPPORT_DTD, false);
- tryToSetStaxProperty(factory,
XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
trySetStaxSecurityManager(factory);
return factory;
diff --git
a/tika-core/src/test/java/org/apache/tika/utils/XMLReaderUtilsTest.java
b/tika-core/src/test/java/org/apache/tika/utils/XMLReaderUtilsTest.java
index 42eb3a84d0..3a70f0aefc 100644
--- a/tika-core/src/test/java/org/apache/tika/utils/XMLReaderUtilsTest.java
+++ b/tika-core/src/test/java/org/apache/tika/utils/XMLReaderUtilsTest.java
@@ -17,6 +17,8 @@
package org.apache.tika.utils;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.ByteArrayInputStream;
@@ -31,6 +33,8 @@ import java.util.NoSuchElementException;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.stream.events.XMLEvent;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;
@@ -138,6 +142,75 @@ public class XMLReaderUtilsTest {
}
}
+ @ParameterizedTest
+ @ValueSource(booleans = {false, true})
+ public void testStaxRejectsSmallInternalEntity(boolean eventReader) throws
Exception {
+ // A single expansion stays below the limit, so this specifically
guards disabled DTD processing.
+ String xml = "<!DOCTYPE root [<!ENTITY value
'INTERNAL_CONTENT'>]><root>&value;</root>";
+ XMLInputFactory factory = XMLReaderUtils.getXMLInputFactory(new
ParseContext());
+ if (eventReader) {
+ XMLEventReader reader = factory.createXMLEventReader(new
StringReader(xml));
+ try {
+ assertThrows(XMLStreamException.class, () -> {
+ while (reader.hasNext()) {
+ reader.nextEvent();
+ }
+ });
+ } finally {
+ reader.close();
+ }
+ } else {
+ XMLStreamReader reader = factory.createXMLStreamReader(new
StringReader(xml));
+ try {
+ assertThrows(XMLStreamException.class, () -> {
+ while (reader.hasNext()) {
+ reader.next();
+ }
+ });
+ } finally {
+ reader.close();
+ }
+ }
+ }
+
+ @Test
+ public void testStaxNamespaceAware() throws Exception {
+ // Coverage only: provider defaults preserve this behavior even
without Tika's explicit settings.
+ XMLStreamReader reader =
XMLReaderUtils.getXMLInputFactory().createXMLStreamReader(
+ new StringReader("<p:root xmlns:p='urn:tika:test'
p:flag='value'/>"));
+ try {
+ assertEquals(XMLStreamReader.START_ELEMENT, reader.nextTag());
+ assertEquals("root", reader.getLocalName());
+ assertEquals("urn:tika:test", reader.getNamespaceURI());
+ assertEquals("value", reader.getAttributeValue("urn:tika:test",
"flag"));
+ } finally {
+ reader.close();
+ }
+ }
+
+ @Test
+ public void testStaxDoesNotExposeReadableExternalEntity(@TempDir Path
tempDir) throws Exception {
+ // Coverage only: Commons Secure XML also blocks this content when DTD
support is enabled.
+ Path external = tempDir.resolve("entity.txt");
+ Files.writeString(external, "EXTERNAL_CONTENT",
StandardCharsets.UTF_8);
+ String xml = "<!DOCTYPE root [<!ENTITY value SYSTEM '" +
external.toUri() + "'>]><root>&value;</root>";
+ XMLEventReader reader =
XMLReaderUtils.getXMLInputFactory().createXMLEventReader(new StringReader(xml));
+ StringBuilder text = new StringBuilder();
+ try {
+ while (reader.hasNext()) {
+ XMLEvent event = reader.nextEvent();
+ if (event.isCharacters()) {
+ text.append(event.asCharacters().getData());
+ }
+ }
+ } catch (XMLStreamException e) {
+ // Rejecting the entity is also acceptable; inspect any content
delivered before rejection.
+ } finally {
+ reader.close();
+ }
+ assertFalse(text.toString().contains("EXTERNAL_CONTENT"),
text.toString());
+ }
+
@Test
public void testStax() throws Exception {
for (String xml : EXTERNAL_ENTITY_XMLS) {