/
XmlProvider.java
265 lines (208 loc) · 9.79 KB
/
XmlProvider.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
/*
* 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.activemq.artemis.utils;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import javax.xml.validation.Validator;
import java.io.InputStream;
import java.io.Reader;
import java.net.URL;
import java.util.Map;
import org.w3c.dom.ls.LSInput;
import org.xml.sax.SAXException;
public class XmlProvider {
public static final String ARTEMIS_DISABLE_XXE_PROPERTY = "artemis.disableXxe";
public static final String XINCLUDE_AWARE_PROPERTY = "XINCLUDE_AWARE";
public static final String NAMESPACE_AWARE_PROPERTY = "NAMESPACE_AWARE";
public static final String IGNORE_COMMENTS_PROPERTY = "IGNORE_COMMENTS";
public static final String IGNORE_ELEMENT_CONTENT_WHITESPACE_PROPERTY = "IGNORE_ELEMENT_CONTENT_WHITESPACE";
private static final String ACTIVEMQ_CORE_NS = "urn:activemq:core";
private static final String ACTIVEMQ_JMS_NS = "urn:activemq:jms";
private static final String ARTEMIS_XML_SCHEMA_SID = "xml.xsd";
private static final String ARTEMIS_CONFIGURATION_SCHEMA_SID = "artemis-configuration.xsd";
private static final String ARTEMIS_JMS_SCHEMA_SID = "artemis-jms.xsd";
private static final String ARTEMIS_SCHEMA_BASE_URL = "schema/";
private static final String ARTEMIS_XML_SCHEMA_URL = ARTEMIS_SCHEMA_BASE_URL + ARTEMIS_XML_SCHEMA_SID;
private static final String ARTEMIS_CONFIGURATION_SCHEMA_URL = ARTEMIS_SCHEMA_BASE_URL + ARTEMIS_CONFIGURATION_SCHEMA_SID;
private static final String ARTEMIS_JMS_SCHEMA_URL = ARTEMIS_SCHEMA_BASE_URL + ARTEMIS_JMS_SCHEMA_SID;
private static boolean xxeEnabled = !"".equals(System.getProperty(ARTEMIS_DISABLE_XXE_PROPERTY)) &&
!Boolean.parseBoolean(System.getProperty(ARTEMIS_DISABLE_XXE_PROPERTY, Boolean.FALSE.toString()));
public static boolean isXxeEnabled() {
return xxeEnabled;
}
public static void setXxeEnabled(boolean enabled) {
xxeEnabled = enabled;
}
public static DocumentBuilder newDocumentBuilder() throws ParserConfigurationException {
return newDocumentBuilder(null, null);
}
public static DocumentBuilder newDocumentBuilder(Map<String, Boolean> features, Map<String, Boolean> properties) throws ParserConfigurationException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
if (features != null) {
for (Map.Entry<String, Boolean> feature : features.entrySet()) {
factory.setFeature(feature.getKey(), feature.getValue());
}
}
if (properties != null) {
for (Map.Entry<String, Boolean> property : properties.entrySet()) {
if (XINCLUDE_AWARE_PROPERTY.equals(property.getKey())) {
factory.setXIncludeAware(property.getValue());
} else if (NAMESPACE_AWARE_PROPERTY.equals(property.getKey())) {
factory.setNamespaceAware(property.getValue());
} else if (IGNORE_COMMENTS_PROPERTY.equals(property.getKey())) {
factory.setIgnoringComments(property.getValue());
} else if (IGNORE_ELEMENT_CONTENT_WHITESPACE_PROPERTY.equals(property.getKey())) {
factory.setIgnoringElementContentWhitespace(property.getValue());
} else {
throw new IllegalArgumentException("Property not supported: " + property.getKey());
}
}
}
if (!isXxeEnabled()) {
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
factory.setXIncludeAware(false);
factory.setExpandEntityReferences(false);
}
return factory.newDocumentBuilder();
}
public static XMLStreamReader createXMLStreamReader(InputStream inputStream) throws XMLStreamException {
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
if (!isXxeEnabled()) {
// This disables DTDs entirely for that factory
xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
// disable external entities
xmlInputFactory.setProperty("javax.xml.stream.isSupportingExternalEntities", false);
}
return xmlInputFactory.createXMLStreamReader(inputStream);
}
public static Schema newSchema(Source schema, Map<String, Boolean> features) throws SAXException {
return newSchemaFactory(features).newSchema(schema);
}
private static SchemaFactory newSchemaFactory(Map<String, Boolean> features) throws SAXException {
SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
if (features != null) {
for (Map.Entry<String, Boolean> feature : features.entrySet()) {
factory.setFeature(feature.getKey(), feature.getValue());
}
}
if (!isXxeEnabled()) {
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
factory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
factory.setResourceResolver((type, namespaceURI, publicId, systemId, baseURI) -> {
if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(type) && XMLConstants.XML_NS_URI.equals(namespaceURI) && ARTEMIS_XML_SCHEMA_SID.equals(systemId)) {
return newLSInput(publicId, systemId, baseURI, Thread.currentThread().getContextClassLoader().getResourceAsStream(ARTEMIS_XML_SCHEMA_URL));
} else if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(type) && ACTIVEMQ_CORE_NS.equals(namespaceURI) && ARTEMIS_CONFIGURATION_SCHEMA_SID.equals(systemId)) {
return newLSInput(publicId, systemId, baseURI, Thread.currentThread().getContextClassLoader().getResourceAsStream(ARTEMIS_CONFIGURATION_SCHEMA_URL));
} else if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(type) && ACTIVEMQ_JMS_NS.equals(namespaceURI) && ARTEMIS_JMS_SCHEMA_SID.equals(systemId)) {
return newLSInput(publicId, systemId, baseURI, Thread.currentThread().getContextClassLoader().getResourceAsStream(ARTEMIS_JMS_SCHEMA_URL));
}
return null;
});
}
return factory;
}
public static Transformer newTransformer() throws TransformerConfigurationException {
TransformerFactory transformerFactory = TransformerFactory.newInstance();
if (!isXxeEnabled()) {
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
}
return transformerFactory.newTransformer();
}
public static Validator newValidator(URL schema) throws SAXException {
Validator validator = newSchemaFactory(null).newSchema(schema).newValidator();
if (!isXxeEnabled()) {
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
validator.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
}
return validator;
}
private static LSInput newLSInput(String publicId, String systemId, String baseURI, InputStream byteStream) {
return new LSInput() {
@Override
public Reader getCharacterStream() {
return null;
}
@Override
public void setCharacterStream(Reader reader) {
}
@Override
public InputStream getByteStream() {
return byteStream;
}
@Override
public void setByteStream(InputStream inputStream) {
}
@Override
public String getStringData() {
return null;
}
@Override
public void setStringData(String s) {
}
@Override
public String getSystemId() {
return systemId;
}
@Override
public void setSystemId(String s) {
}
@Override
public String getPublicId() {
return publicId;
}
@Override
public void setPublicId(String s) {
}
@Override
public String getBaseURI() {
return baseURI;
}
@Override
public void setBaseURI(String s) {
}
@Override
public String getEncoding() {
return null;
}
@Override
public void setEncoding(String s) {
}
@Override
public boolean getCertifiedText() {
return false;
}
@Override
public void setCertifiedText(boolean b) {
}
};
}
}