1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.xml.secure;
19
20 import static org.apache.commons.xml.secure.AttackTestSupport.LEAKED_MARKER;
21 import static org.apache.commons.xml.secure.AttackTestSupport.resourceUrl;
22 import static org.junit.jupiter.api.Assertions.assertEquals;
23 import static org.junit.jupiter.api.Assertions.assertNotEquals;
24 import static org.junit.jupiter.api.Assumptions.assumeTrue;
25
26 import javax.xml.XMLConstants;
27 import javax.xml.parsers.DocumentBuilder;
28 import javax.xml.parsers.DocumentBuilderFactory;
29
30 import org.junit.jupiter.api.Tag;
31 import org.junit.jupiter.api.Test;
32 import org.w3c.dom.Document;
33 import org.xml.sax.InputSource;
34 import org.xml.sax.SAXException;
35 import org.xml.sax.SAXParseException;
36 import org.xml.sax.helpers.DefaultHandler;
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54 @Tag("dom")
55 class SchemaLocationDomTest {
56
57
58
59
60 private static final String SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
61
62 private static final String INSTANCE = "schema-location-instance.xml";
63
64 private static DocumentBuilderFactory enableXsdValidation(final DocumentBuilderFactory factory) {
65 factory.setNamespaceAware(true);
66 factory.setValidating(true);
67 factory.setAttribute(SCHEMA_LANGUAGE, XMLConstants.W3C_XML_SCHEMA_NS_URI);
68 return factory;
69 }
70
71 private static Document parse(final DocumentBuilderFactory factory) throws Exception {
72 final DocumentBuilder builder = factory.newDocumentBuilder();
73 builder.setErrorHandler(new DefaultHandler() {
74
75
76
77
78
79 @Override
80 public void error(final SAXParseException exception) throws SAXException {
81 throw exception;
82 }
83 });
84 return builder.parse(new InputSource(resourceUrl(INSTANCE).toString()));
85 }
86
87 private static boolean supportsSchemaLanguage() {
88 try {
89 final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
90 factory.setValidating(true);
91 factory.setAttribute(SCHEMA_LANGUAGE, XMLConstants.W3C_XML_SCHEMA_NS_URI);
92 return true;
93 } catch (final Exception e) {
94 return false;
95 }
96 }
97
98 @Test
99 void secureDoesNotFetchExternalSchema() {
100 assumeTrue(supportsSchemaLanguage(), "parser does not support JAXP 1.2 schema-language XSD validation");
101 final DocumentBuilderFactory factory = enableXsdValidation(SecureDocumentBuilderFactory.newInstance());
102
103
104 try {
105 final Document document = parse(factory);
106 assertNotEquals(LEAKED_MARKER, document.getDocumentElement().getAttribute("leak"),
107 "Secured parse must not inline the external schema's default attribute.");
108 } catch (final Exception blocked) {
109
110 }
111 }
112
113 @Test
114 void unconfiguredFetchesExternalSchema() throws Exception {
115 assumeTrue(supportsSchemaLanguage(), "parser does not support JAXP 1.2 schema-language XSD validation");
116 final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
117 factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, false);
118
119 final Document document = parse(enableXsdValidation(factory));
120 assertEquals(LEAKED_MARKER, document.getDocumentElement().getAttribute("leak"),
121 "Permissive parse should have fetched the external schema and inlined its default attribute.");
122 }
123 }