Skip to content

Commit 7f915cc

Browse files
committed
Set secure processing property to XML factory and port XmlUtils changes from v1
1 parent db830ab commit 7f915cc

File tree

8 files changed

+94
-38
lines changed

8 files changed

+94
-38
lines changed

core/src/main/java/software/amazon/awssdk/core/http/StaxResponseHandler.java

Lines changed: 9 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,10 @@
1515

1616
package software.amazon.awssdk.core.http;
1717

18-
import static software.amazon.awssdk.utils.FunctionalUtils.invokeSafely;
19-
2018
import java.io.ByteArrayInputStream;
2119
import java.io.InputStream;
2220
import java.util.Map;
2321
import javax.xml.stream.XMLEventReader;
24-
import javax.xml.stream.XMLInputFactory;
2522
import javax.xml.stream.XMLStreamException;
2623
import software.amazon.awssdk.annotations.ReviewBeforeRelease;
2724
import software.amazon.awssdk.annotations.SdkProtectedApi;
@@ -34,6 +31,7 @@
3431
import software.amazon.awssdk.core.util.StringUtils;
3532
import software.amazon.awssdk.utils.FunctionalUtils.UnsafeFunction;
3633
import software.amazon.awssdk.utils.Logger;
34+
import software.amazon.awssdk.utils.XmlUtils;
3735

3836
/**
3937
* Default implementation of HttpResponseHandler that handles a successful
@@ -47,10 +45,6 @@
4745
public class StaxResponseHandler<T> implements HttpResponseHandler<T> {
4846
private static final Logger log = Logger.loggerFor(StaxResponseHandler.class);
4947

50-
/**
51-
* Shared factory for creating XML event readers.
52-
*/
53-
private static final XMLInputFactory XML_INPUT_FACTORY = createXmlInputFactory();
5448
/**
5549
* The StAX unmarshaller to use when handling the response.
5650
*/
@@ -90,10 +84,7 @@ public T handle(HttpResponse response, ExecutionAttributes executionAttributes)
9084
content = new ByteArrayInputStream("<eof/>".getBytes(StringUtils.UTF8));
9185
}
9286

93-
XMLEventReader eventReader;
94-
synchronized (XML_INPUT_FACTORY) {
95-
eventReader = XML_INPUT_FACTORY.createXMLEventReader(content);
96-
}
87+
XMLEventReader eventReader = XmlUtils.xmlInputFactory().createXMLEventReader(content);
9788

9889
try {
9990
StaxUnmarshallerContext unmarshallerContext = new StaxUnmarshallerContext(eventReader, response.getHeaders());
@@ -128,7 +119,7 @@ protected ResponseMetadata getResponseMetadata(Map<String, String> metadata) {
128119
* from service responses.
129120
*
130121
* @param unmarshallerContext The unmarshaller context used to configure a service's response
131-
* data.
122+
* data.
132123
*/
133124
protected void registerAdditionalMetadataExpressions(StaxUnmarshallerContext unmarshallerContext) {
134125
}
@@ -150,10 +141,10 @@ public boolean needsConnectionLeftOpen() {
150141
* for example).
151142
*
152143
* @param unmarshaller Unmarshaller for response POJO.
153-
* @param <ResponseT> Response POJO type.
144+
* @param <ResponseT> Response POJO type.
154145
*/
155146
public static <ResponseT> HttpResponseHandler<ResponseT> createStreamingResponseHandler(
156-
Unmarshaller<ResponseT, StaxUnmarshallerContext> unmarshaller) {
147+
Unmarshaller<ResponseT, StaxUnmarshallerContext> unmarshaller) {
157148
UnsafeFunction<HttpResponse, ResponseT> unmarshallFunction = response -> unmarshallStreaming(unmarshaller, response);
158149
return new HttpResponseHandler<ResponseT>() {
159150
@Override
@@ -168,35 +159,21 @@ public boolean needsConnectionLeftOpen() {
168159
};
169160
}
170161

171-
/**
172-
* Create an {@link XMLInputFactory} with features that may cause security problems disabled
173-
* @return an instance of {@link XMLInputFactory}
174-
*/
175-
private static XMLInputFactory createXmlInputFactory() {
176-
XMLInputFactory factory = XMLInputFactory.newInstance();
177-
factory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
178-
factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
179-
return factory;
180-
}
181-
182162
/**
183163
* Unmarshalls a streaming HTTP response into a POJO. Does not touch the content since that's consumed by the response
184164
* handler (either {@link StreamingResponseHandler} or {@link AsyncResponseHandler}).
185165
*
186166
* @param unmarshaller Unmarshaller for resposne type.
187-
* @param response HTTP response
188-
* @param <ResponseT> Response POJO Type.
167+
* @param response HTTP response
168+
* @param <ResponseT> Response POJO Type.
189169
* @return Unmarshalled response type.
190170
* @throws Exception if error occurs during unmarshalling.
191171
*/
192172
private static <ResponseT> ResponseT unmarshallStreaming(Unmarshaller<ResponseT, StaxUnmarshallerContext> unmarshaller,
193173
HttpResponse response) throws Exception {
194174
// Create a dummy event reader to make unmarshallers happy
195-
XMLEventReader eventReader;
196-
synchronized (XML_INPUT_FACTORY) {
197-
eventReader = invokeSafely(() -> XML_INPUT_FACTORY
198-
.createXMLEventReader(new ByteArrayInputStream("<eof/>".getBytes(StringUtils.UTF8))));
199-
}
175+
XMLEventReader eventReader = XmlUtils.xmlInputFactory().createXMLEventReader(
176+
new ByteArrayInputStream("<eof/>".getBytes(StringUtils.UTF8)));
200177

201178
StaxUnmarshallerContext unmarshallerContext = new StaxUnmarshallerContext(eventReader, response.getHeaders());
202179
unmarshallerContext.registerMetadataExpression("ResponseMetadata/RequestId", 2, ResponseMetadata.AWS_REQUEST_ID);

core/src/main/java/software/amazon/awssdk/core/util/XpathUtils.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import org.xml.sax.SAXException;
3939
import org.xml.sax.SAXParseException;
4040
import software.amazon.awssdk.utils.Base64Utils;
41+
import software.amazon.awssdk.utils.XmlUtils;
4142

4243
/**
4344
* Utility methods for extracting data from XML documents using Xpath
@@ -164,7 +165,7 @@ public static Document documentFrom(InputStream is)
164165
throws SAXException, IOException, ParserConfigurationException {
165166
is = new NamespaceRemovingInputStream(is);
166167
// DocumentBuilderFactory is not thread safe
167-
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
168+
DocumentBuilderFactory factory = XmlUtils.documentBuilderFactory();
168169
DocumentBuilder builder = factory.newDocumentBuilder();
169170
// ensure that parser writes error/warning messages to the logger
170171
// rather than stderr

services/simpledb/src/test/java/software/amazon/awssdk/services/simpledb/transform/DomainMetadataResultUnmarshallerTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.junit.Test;
2323
import software.amazon.awssdk.core.runtime.transform.StaxUnmarshallerContext;
2424
import software.amazon.awssdk.services.simpledb.model.DomainMetadataResponse;
25+
import software.amazon.awssdk.utils.XmlUtils;
2526

2627
public class DomainMetadataResultUnmarshallerTest {
2728

@@ -30,7 +31,7 @@ public class DomainMetadataResultUnmarshallerTest {
3031
*/
3132
@Test
3233
public final void testXpathUnmarshaller() throws Exception {
33-
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
34+
XMLInputFactory xmlInputFactory = XmlUtils.xmlInputFactory();
3435
XMLEventReader eventReader = xmlInputFactory.createXMLEventReader(DomainMetadataResultUnmarshallerTest.class
3536
.getResourceAsStream("DomainMetadataResponse.xml"));
3637
StaxUnmarshallerContext unmarshallerContext = new StaxUnmarshallerContext(eventReader);

services/simpledb/src/test/java/software/amazon/awssdk/services/simpledb/transform/GetAttributesResultUnmarshallerTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.junit.Test;
2323
import software.amazon.awssdk.core.runtime.transform.StaxUnmarshallerContext;
2424
import software.amazon.awssdk.services.simpledb.model.GetAttributesResponse;
25+
import software.amazon.awssdk.utils.XmlUtils;
2526

2627
public class GetAttributesResultUnmarshallerTest {
2728

@@ -30,7 +31,7 @@ public class GetAttributesResultUnmarshallerTest {
3031
*/
3132
@Test
3233
public final void testUnmarshall() throws Exception {
33-
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
34+
XMLInputFactory xmlInputFactory = XmlUtils.xmlInputFactory();
3435
XMLEventReader eventReader = xmlInputFactory.createXMLEventReader(DomainMetadataResultUnmarshallerTest.class
3536
.getResourceAsStream("GetAttributesResponse.xml"));
3637
StaxUnmarshallerContext unmarshallerContext = new StaxUnmarshallerContext(eventReader);

services/simpledb/src/test/java/software/amazon/awssdk/services/simpledb/transform/ListDomainsResultUnmarshallerTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.junit.Test;
2323
import software.amazon.awssdk.core.runtime.transform.StaxUnmarshallerContext;
2424
import software.amazon.awssdk.services.simpledb.model.ListDomainsResponse;
25+
import software.amazon.awssdk.utils.XmlUtils;
2526

2627
public class ListDomainsResultUnmarshallerTest {
2728

@@ -30,7 +31,7 @@ public class ListDomainsResultUnmarshallerTest {
3031
*/
3132
@Test
3233
public final void testUnmarshall() throws Exception {
33-
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
34+
XMLInputFactory xmlInputFactory = XmlUtils.xmlInputFactory();
3435
XMLEventReader eventReader = xmlInputFactory.createXMLEventReader(DomainMetadataResultUnmarshallerTest.class
3536
.getResourceAsStream("ListDomainsResponse.xml"));
3637
StaxUnmarshallerContext unmarshallerContext = new StaxUnmarshallerContext(eventReader);

services/simpledb/src/test/java/software/amazon/awssdk/services/simpledb/transform/SelectResultUnmarshallerTest.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import software.amazon.awssdk.core.runtime.transform.StaxUnmarshallerContext;
2424
import software.amazon.awssdk.services.simpledb.model.Item;
2525
import software.amazon.awssdk.services.simpledb.model.SelectResponse;
26+
import software.amazon.awssdk.utils.XmlUtils;
2627

2728
public class SelectResultUnmarshallerTest {
2829

@@ -31,7 +32,7 @@ public class SelectResultUnmarshallerTest {
3132
*/
3233
@Test
3334
public final void testUnmarshall() throws Exception {
34-
XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
35+
XMLInputFactory xmlInputFactory = XmlUtils.xmlInputFactory();
3536
XMLEventReader eventReader = xmlInputFactory.createXMLEventReader(DomainMetadataResultUnmarshallerTest.class
3637
.getResourceAsStream("SelectResponse.xml"));
3738
StaxUnmarshallerContext unmarshallerContext = new StaxUnmarshallerContext(eventReader);

test/protocol-tests-core/src/main/java/software/amazon/awssdk/protocol/asserts/marshalling/XmlAsserts.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@
1818
import static org.junit.Assert.fail;
1919

2020
import java.io.StringWriter;
21+
import javax.xml.XMLConstants;
2122
import javax.xml.parsers.DocumentBuilder;
2223
import javax.xml.parsers.DocumentBuilderFactory;
2324
import javax.xml.parsers.ParserConfigurationException;
2425
import javax.xml.transform.OutputKeys;
2526
import javax.xml.transform.Transformer;
27+
import javax.xml.transform.TransformerConfigurationException;
2628
import javax.xml.transform.TransformerFactory;
2729
import javax.xml.transform.dom.DOMSource;
2830
import javax.xml.transform.stream.StreamResult;
@@ -71,11 +73,18 @@ private static String formatXml(String xmlDocumentString) throws Exception {
7173
}
7274

7375
private static String formatXml(Document xmlDocument) throws Exception {
74-
Transformer transformer = TransformerFactory.newInstance().newTransformer();
76+
Transformer transformer = transformerFactory().newTransformer();
7577
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
7678
StreamResult result = new StreamResult(new StringWriter());
7779
DOMSource source = new DOMSource(xmlDocument);
7880
transformer.transform(source, result);
7981
return result.getWriter().toString();
8082
}
83+
84+
private static TransformerFactory transformerFactory() throws TransformerConfigurationException {
85+
TransformerFactory factory = TransformerFactory.newInstance();
86+
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
87+
factory.setFeature(XMLConstants.ACCESS_EXTERNAL_DTD, false);
88+
return factory;
89+
}
8190
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright 2010-2018 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
16+
package software.amazon.awssdk.utils;
17+
18+
import javax.xml.XMLConstants;
19+
import javax.xml.parsers.DocumentBuilderFactory;
20+
import javax.xml.parsers.ParserConfigurationException;
21+
import javax.xml.stream.XMLInputFactory;
22+
23+
public final class XmlUtils {
24+
25+
/**
26+
* Shared factory for creating XML event readers
27+
*/
28+
private static final ThreadLocal<XMLInputFactory> XML_INPUT_FACTORY =
29+
ThreadLocal.withInitial(XmlUtils::createXmlInputFactory);
30+
31+
private XmlUtils() {
32+
}
33+
34+
/**
35+
* @return A {@link ThreadLocal} copy of {@link XMLInputFactory}.
36+
*/
37+
public static XMLInputFactory xmlInputFactory() {
38+
return XML_INPUT_FACTORY.get();
39+
}
40+
41+
/**
42+
* Disables certain dangerous features that attempt to automatically fetch DTDs
43+
*
44+
* See <a href="https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet">OWASP XXE Cheat Sheet</a>
45+
*/
46+
public static DocumentBuilderFactory documentBuilderFactory() throws ParserConfigurationException {
47+
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
48+
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
49+
factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
50+
factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
51+
return factory;
52+
}
53+
54+
/**
55+
* Disables certain dangerous features that attempt to automatically fetch DTDs
56+
*
57+
* See <a href="https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet">OWASP XXE Cheat Sheet</a>
58+
*/
59+
private static XMLInputFactory createXmlInputFactory() {
60+
XMLInputFactory factory = XMLInputFactory.newInstance();
61+
factory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
62+
factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
63+
return factory;
64+
}
65+
}

0 commit comments

Comments
 (0)