Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/test/java/org/apache/commons/xml/AttackTestSupport.java
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,13 @@ public void warning(final TransformerException exception) {
* <p>Android's {@code KXmlParser} currently fails this test.</p>
*/
static final boolean DOM_RESOLVES_INTERNAL_ENTITIES = probeDomResolvesInternalEntities();
/** {@code true} when the platform's default DOM factory (and its builders) support parser-attached schemas; Android inherits the throwing JAXP base methods. */
static final boolean DOM_SUPPORTS_SCHEMA = supportsConfiguration(() -> DocumentBuilderFactory.newInstance().setSchema(null));
/** {@code true} when the platform's default DOM factory accepts {@link XMLConstants#FEATURE_SECURE_PROCESSING}; Android's factory rejects it. */
static final boolean DOM_SUPPORTS_SECURE_PROCESSING =
supportsConfiguration(() -> DocumentBuilderFactory.newInstance().setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true));
/** {@code true} when the platform's default DOM factory (and its builders) support the XInclude switches; Android inherits the throwing JAXP base methods. */
static final boolean DOM_SUPPORTS_XINCLUDE = supportsConfiguration(() -> DocumentBuilderFactory.newInstance().setXIncludeAware(false));
/** {@code true} when running on Android (Dalvik / ART), {@code false} on any standard JVM. Probed once via {@code Class.forName} on {@code android.os.Build}. */
static final boolean IS_ANDROID = probeAndroid();
/**
Expand All @@ -199,6 +206,15 @@ public void warning(final TransformerException exception) {
* presence is the leak signal.</p>
*/
static final String LEAKED_MARKER = "All your base are belong to us";
/** {@code true} when the platform's default SAX parser supports {@code reset()}; Android inherits the throwing JAXP base method. */
static final boolean SAX_SUPPORTS_RESET = supportsConfiguration(() -> SAXParserFactory.newInstance().newSAXParser().reset());
/** {@code true} when the platform's default SAX factory (and its parsers) support parser-attached schemas; Android inherits the throwing JAXP base methods. */
static final boolean SAX_SUPPORTS_SCHEMA = supportsConfiguration(() -> SAXParserFactory.newInstance().setSchema(null));
/** {@code true} when the platform's default SAX factory accepts {@link XMLConstants#FEATURE_SECURE_PROCESSING}; Android's Expat rejects it. */
static final boolean SAX_SUPPORTS_SECURE_PROCESSING =
supportsConfiguration(() -> SAXParserFactory.newInstance().setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true));
/** {@code true} when the platform's default SAX factory (and its parsers) support the XInclude switches; Android inherits the throwing JAXP base methods. */
static final boolean SAX_SUPPORTS_XINCLUDE = supportsConfiguration(() -> SAXParserFactory.newInstance().setXIncludeAware(false));
static final StrictReporter STRICT_REPORTER = new StrictReporter();
/**
* Woodstox's entity-count limit property; it ignores the JDK properties above and enforces its own default of {@code 100000}.
Expand Down Expand Up @@ -1032,6 +1048,16 @@ static XMLReader strictXMLReader(final XMLReader reader) {
return reader;
}

/** Probes a JAXP configuration call once at class load; {@code false} where the platform default implementation throws (for example Android). */
private static boolean supportsConfiguration(final Executable action) {
try {
action.execute();
return true;
} catch (final Throwable t) {
return false;
}
}

/** Runs the action and silently swallows any thrown exception; used to apply best-effort permissive-side flags that may not be supported. */
private static void suppressException(final Executable action) {
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilderFactory;

import org.junit.jupiter.api.Assumptions;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

Expand All @@ -35,6 +36,7 @@ class SecureDocumentBuilderFactoryTest {

@Test
void createsSecureBuildersFromEveryStaticEntryPoint() throws Exception {
Assumptions.assumeTrue(AttackTestSupport.DOM_RESOLVES_INTERNAL_ENTITIES, "the platform DOM is left unwrapped: it does not resolve user-defined entities");
assertInstanceOf(SecureDocumentBuilder.class, SecureDocumentBuilderFactory.newInstance().newDocumentBuilder());
assertInstanceOf(SecureDocumentBuilder.class, SecureDocumentBuilderFactory.newDefaultInstance().newDocumentBuilder());
assertInstanceOf(SecureDocumentBuilder.class, SecureDocumentBuilderFactory.newNSInstance().newDocumentBuilder());
Expand All @@ -43,6 +45,7 @@ void createsSecureBuildersFromEveryStaticEntryPoint() throws Exception {

@Test
void forwardsEverySupportedFactoryConfiguration() throws Exception {
Assumptions.assumeTrue(AttackTestSupport.DOM_RESOLVES_INTERNAL_ENTITIES, "the platform DOM is left unwrapped: it does not resolve user-defined entities");
final DocumentBuilderFactory factory = SecureDocumentBuilderFactory.newInstance();
factory.setCoalescing(true);
factory.setExpandEntityReferences(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,21 @@ void forwardsDocumentBuilderStateAndDomImplementation() throws Exception {
final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setValidating(false);
factory.setXIncludeAware(false);
factory.setSchema(null);
if (AttackTestSupport.DOM_SUPPORTS_XINCLUDE) {
factory.setXIncludeAware(false);
}
if (AttackTestSupport.DOM_SUPPORTS_SCHEMA) {
factory.setSchema(null);
}
final SecureDocumentBuilder builder = new SecureDocumentBuilder(factory.newDocumentBuilder());
assertTrue(builder.isNamespaceAware());
assertFalse(builder.isValidating());
assertFalse(builder.isXIncludeAware());
assertNull(builder.getSchema());
if (AttackTestSupport.DOM_SUPPORTS_XINCLUDE) {
assertFalse(builder.isXIncludeAware());
}
if (AttackTestSupport.DOM_SUPPORTS_SCHEMA) {
assertNull(builder.getSchema());
}
assertNotNull(builder.getDOMImplementation());
}
}
Loading
Loading