BUG-7057: introduce UntrustedXML class 27/47727/5
authorRobert Varga <rovarga@cisco.com>
Fri, 28 Oct 2016 10:21:46 +0000 (12:21 +0200)
committerRobert Varga <rovarga@cisco.com>
Sat, 29 Oct 2016 00:49:26 +0000 (02:49 +0200)
This adds the basic newDocumentBuilder() and newSAXParser()
methods. The class is expected to grow more methods in future.

Change-Id: I019891af5f9e8be15eda158bb6e40243dcec0614
Signed-off-by: Robert Varga <rovarga@cisco.com>
common/util/src/main/java/org/opendaylight/yangtools/util/xml/UntrustedXML.java [new file with mode: 0644]

diff --git a/common/util/src/main/java/org/opendaylight/yangtools/util/xml/UntrustedXML.java b/common/util/src/main/java/org/opendaylight/yangtools/util/xml/UntrustedXML.java
new file mode 100644 (file)
index 0000000..39e32b6
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.yangtools.util.xml;
+
+import com.google.common.annotations.Beta;
+import javax.annotation.Nonnull;
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import org.xml.sax.SAXException;
+
+/**
+ * Set of utility methods for instantiating parser that deal with untrusted XML sources.
+ *
+ * @author Robert Varga
+ */
+@Beta
+public final class UntrustedXML {
+    private static final DocumentBuilderFactory DBF;
+    static {
+        final DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
+        f.setCoalescing(true);
+        f.setExpandEntityReferences(false);
+        f.setIgnoringElementContentWhitespace(true);
+        f.setIgnoringComments(true);
+        f.setNamespaceAware(true);
+        f.setXIncludeAware(false);
+        try {
+            f.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+            f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+            f.setFeature("http://xml.org/sax/features/external-general-entities", false);
+            f.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+        } catch (final ParserConfigurationException e) {
+            throw new ExceptionInInitializerError(e);
+        }
+        DBF = f;
+    }
+
+    private static final SAXParserFactory SPF;
+    static {
+        final SAXParserFactory f = SAXParserFactory.newInstance();
+        f.setNamespaceAware(true);
+        f.setXIncludeAware(false);
+        try {
+            f.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+            f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+            f.setFeature("http://xml.org/sax/features/external-general-entities", false);
+            f.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+        } catch (final Exception e) {
+            throw new ExceptionInInitializerError(e);
+        }
+
+        SPF = f;
+    }
+
+    /**
+     * Create a new {@link DocumentBuilder} for dealing with untrusted XML data. This method is equivalent to
+     * {@link DocumentBuilderFactory#newDocumentBuilder()}, except it does not throw a checked exception.
+     *
+     * @return A new DocumentBuilder
+     * @throws UnsupportedOperationException if the runtime fails to instantiate a good enough builder
+     */
+    public static @Nonnull DocumentBuilder newDocumentBuilder() {
+        try {
+            return DBF.newDocumentBuilder();
+        } catch (ParserConfigurationException e) {
+            throw new UnsupportedOperationException("Failed to instantiate a DocumentBuilder", e);
+        }
+    }
+
+    /**
+     * Create a new {@link SAXParser} for dealing with untrusted XML data. This method is equivalent to
+     * {@link SAXParserFactory#newSAXParser()}, except it does not throw a checked exception.
+     *
+     * @return A new SAXParser
+     * @throws UnsupportedOperationException if the runtime fails to instantiate a good enough builder
+     */
+    public static @Nonnull SAXParser newSAXParser() {
+        try {
+            return SPF.newSAXParser();
+        } catch (ParserConfigurationException | SAXException e) {
+            throw new UnsupportedOperationException("Failed to instantiate a SAXParser", e);
+        }
+    }
+}