• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

xmlunit / xmlunit / 91fcc18b-ffe6-42ea-a192-dbc978659451

20 Jun 2026 03:02PM UTC coverage: 91.747% (-0.04%) from 91.787%
91fcc18b-ffe6-42ea-a192-dbc978659451

push

circleci

web-flow
Merge pull request #331 from jmestwa-coder/jaxp-validator-external-dtd

add opt-in to disable external DTD access in JAXPValidator

4034 of 4746 branches covered (85.0%)

13 of 17 new or added lines in 1 file covered. (76.47%)

6 existing lines in 1 file now uncovered.

11828 of 12892 relevant lines covered (91.75%)

2.34 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.47
/xmlunit-core/src/main/java/org/xmlunit/validation/JAXPValidator.java
1
/*
2
  This file is licensed to You under the Apache License, Version 2.0
3
  (the "License"); you may not use this file except in compliance with
4
  the License.  You may obtain a copy of the License at
5

6
  http://www.apache.org/licenses/LICENSE-2.0
7

8
  Unless required by applicable law or agreed to in writing, software
9
  distributed under the License is distributed on an "AS IS" BASIS,
10
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
  See the License for the specific language governing permissions and
12
  limitations under the License.
13
*/
14
package org.xmlunit.validation;
15

16
import javax.xml.XMLConstants;
17
import javax.xml.transform.Source;
18
import javax.xml.validation.Schema;
19
import javax.xml.validation.SchemaFactory;
20
import org.xmlunit.XMLUnitException;
21
import org.xml.sax.SAXException;
22
import org.xml.sax.SAXNotRecognizedException;
23
import org.xml.sax.SAXNotSupportedException;
24
import org.xml.sax.SAXParseException;
25

26
/**
27
 * Validator using the javax.xml.validation namespace.
28
 *
29
 * <p>An implementation detail of {@code
30
 * javax.xml.validation.Validator} leaks into this class: any {@code
31
 * xsi:schemaLocation} or {@code xsi:noSchemaLocation} attribute of
32
 * the instance document will be ignored if any schema source has been
33
 * set.  This means you must either specify all sources or none of
34
 * them to successfully validate instances.</p>
35
 *
36
 * <p><strong>Security note:</strong> like the rest of the {@code
37
 * validation} package this class does not restrict external DTD access
38
 * by default - that has been a conscious decision since XMLUnit 2.6.0
39
 * because schema validation often needs to load external resources. An
40
 * instance document with a {@code DOCTYPE} that declares an external
41
 * entity may therefore cause that entity to be resolved while it is
42
 * validated. If you validate untrusted input use {@link
43
 * #setDisableExternalDtdAccess setDisableExternalDtdAccess(true)} to
44
 * forbid this.</p>
45
 */
46
public class JAXPValidator extends Validator {
47
    private final String language;
48
    private final SchemaFactory factory;
49
    private Schema schema;
50
    private boolean disableExternalDtdAccess;
51

52
    /**
53
     * Creates a validator for the given schema language using the default SchemaFactory.
54
     * @param language the schema language
55
     */
56
    public JAXPValidator(String language) {
57
        this(language, null);
1✔
58
    }
1✔
59

60
    /**
61
     * Creates a validator for the given schema language using a custom SchemaFactory.
62
     * @param language the schema language
63
     * @param factory the factory to use
64
     */
65
    public JAXPValidator(String language, SchemaFactory factory) {
1✔
66
        this.language = language;
1✔
67
        this.factory = factory;
1✔
68
    }
1✔
69

70
    /**
71
     * Sets the schema to use in instance validation directly rather
72
     * than via {@link #setSchemaSource}.
73
     * @since XMLUnit 2.3.0
74
     * @param s the schema as Source
75
     */
76
    public final void setSchema(Schema s) {
77
        schema = s;
1✔
78
    }
1✔
79

80
    /**
81
     * Whether external DTD access should be forbidden when parsing the
82
     * schema and validating instances.
83
     *
84
     * <p>The default is {@code false}, leaving external DTD access
85
     * enabled as it has been since XMLUnit 2.6.0. Setting this to
86
     * {@code true} sets the {@code accessExternalDTD} property to the
87
     * empty string on the {@code SchemaFactory} and {@code Validator}
88
     * used, which closes the XXE vector when validating untrusted
89
     * instances. The {@code accessExternalSchema} property is left
90
     * untouched so {@code xs:import} and {@code xsi:schemaLocation}
91
     * keep working.</p>
92
     *
93
     * @since XMLUnit 2.12.1
94
     * @param disable whether to forbid external DTD access
95
     */
96
    public void setDisableExternalDtdAccess(boolean disable) {
97
        disableExternalDtdAccess = disable;
1✔
98
    }
1✔
99

100
    private SchemaFactory getFactory() {
101
        SchemaFactory f = factory == null ? SchemaFactory.newInstance(language) : factory;
1✔
102
        if (disableExternalDtdAccess) {
1✔
103
            restrictExternalDtdAccess(f);
1✔
104
        }
105
        return f;
1✔
106
    }
107

108
    private static void restrictExternalDtdAccess(SchemaFactory f) {
109
        try {
110
            f.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
1✔
NEW
111
        } catch (SAXNotRecognizedException ex) {
×
112
            // property not supported, nothing we can do
NEW
113
        } catch (SAXNotSupportedException ex) {
×
114
            // property not supported, nothing we can do
115
        }
1✔
116
    }
1✔
117

118
    private static void restrictExternalDtdAccess(javax.xml.validation.Validator v) {
119
        try {
120
            v.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
1✔
NEW
121
        } catch (SAXNotRecognizedException ex) {
×
122
            // property not supported, nothing we can do
NEW
123
        } catch (SAXNotSupportedException ex) {
×
124
            // property not supported, nothing we can do
125
        }
1✔
126
    }
1✔
127

128
    @Override public ValidationResult validateSchema() {
129
        ValidationHandler v = new ValidationHandler();
1✔
130
        SchemaFactory f = getFactory();
1✔
131
        f.setErrorHandler(v);
1✔
132
        try {
133
            f.newSchema(getSchemaSources());
1✔
134
        } catch (SAXParseException e) {
1✔
135
            v.error((SAXParseException) e);
1✔
136
        } catch (SAXException e) {
1✔
137
            throw new XMLUnitException(e);
1✔
138
        } finally {
139
            f.setErrorHandler(null);
1✔
140
        }
141
        return v.getResult();
1✔
142
    }
143

144
    @Override public ValidationResult validateInstance(Source s) {
145
        Schema schema;
146
        try {
147
            schema = getSchema();
1✔
148
        } catch (SAXException e) {
1✔
149
            throw new XMLUnitException("The schema is invalid", e);
1✔
150
        }
1✔
151
        ValidationHandler v = new ValidationHandler();
1✔
152
        javax.xml.validation.Validator val = schema.newValidator();
1✔
153
        if (disableExternalDtdAccess) {
1✔
154
            restrictExternalDtdAccess(val);
1✔
155
        }
156
        val.setErrorHandler(v);
1✔
157
        try {
158
            val.validate(s);
1✔
159
        } catch (SAXParseException e) {
1✔
160
            v.error((SAXParseException) e);
1✔
161
        } catch (SAXException e) {
1✔
162
            throw new XMLUnitException(e);
1✔
163
        } catch (java.io.IOException e) {
×
164
            throw new XMLUnitException(e);
×
165
        }
1✔
166
        return v.getResult();
1✔
167
    }
168

169
    private Schema getSchema() throws SAXException {
170
        if (schema != null) {
1✔
171
            return schema;
1✔
172
        }
173
        Source[] sources = getSchemaSources();
1✔
174
        return sources.length > 0 ? getFactory().newSchema(sources)
1✔
175
            : getFactory().newSchema();
1✔
176
    }
177
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc