You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by jo...@apache.org on 2022/04/14 15:27:36 UTC
[nifi] branch support/nifi-1.16 updated: NIFI-9901 Added nifi-xml-processing to nifi-commons
This is an automated email from the ASF dual-hosted git repository.
joewitt pushed a commit to branch support/nifi-1.16
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/support/nifi-1.16 by this push:
new 5d94e7f7d5 NIFI-9901 Added nifi-xml-processing to nifi-commons
5d94e7f7d5 is described below
commit 5d94e7f7d594e600d8eb00329bb38b99d46ec66b
Author: exceptionfactory <ex...@apache.org>
AuthorDate: Tue Apr 12 15:32:27 2022 -0500
NIFI-9901 Added nifi-xml-processing to nifi-commons
- Refactored XML parsing to use providers from nifi-xml-processing
- Configured spotbugs-maven-plugin with findsecbugs-plugin in nifi-xml-processing
- Disabled Validate DTD in default configuration for EvaluateXPath and EvaluateXQuery
- Replaced configuration of DocumentBuilder and streaming XML Readers with shared components
- Removed XML utilities from nifi-security-utils
- Moved Commons Configuration classes to nifi-lookup-services
This closes #5962
Signed-off-by: Paul Grey <gr...@apache.org>
---
minifi/minifi-bootstrap/pom.xml | 4 +
.../minifi/bootstrap/util/ConfigTransformer.java | 19 +-
.../bootstrap/util/ConfigTransformerTest.java | 39 ++--
minifi/pom.xml | 5 +
nifi-bootstrap/pom.xml | 5 +
.../nifi/bootstrap/NotificationServiceManager.java | 36 +---
nifi-commons/nifi-security-utils/pom.xml | 66 ------
.../org/apache/nifi/security/xml/XmlUtils.java | 102 ---------
.../apache/nifi/security/xml/XmlUtilsTest.groovy | 100 ---------
nifi-commons/nifi-single-user-utils/pom.xml | 5 +
.../writer/StandardLoginCredentialsWriter.java | 12 +-
nifi-commons/nifi-site-to-site-client/pom.xml | 5 +
.../remote/cluster/ClusterNodeInformation.java | 12 +-
nifi-commons/nifi-xml-processing/pom.xml | 55 +++++
.../nifi/xml/processing/ProcessingException.java | 32 +++
.../nifi/xml/processing/ProcessingFeature.java | 53 +++++
.../xml/processing/parsers/DocumentProvider.java | 41 ++++
.../parsers/StandardDocumentProvider.java | 126 +++++++++++
.../nifi/xml/processing/sax/InputSourceParser.java | 33 +++
.../processing/sax/StandardInputSourceParser.java | 90 ++++++++
.../stream/StandardXMLEventReaderProvider.java | 51 +++++
.../stream/StandardXMLStreamReaderProvider.java | 51 +++++
.../processing/stream/XMLEventReaderProvider.java | 33 +++
.../processing/stream/XMLStreamReaderProvider.java | 33 +++
.../xml/processing/validation/SchemaValidator.java | 33 +++
.../validation/StandardSchemaValidator.java | 59 +++++
.../nifi/xml/processing/ResourceProvider.java | 65 ++++++
.../parsers/StandardDocumentProviderTest.java | 108 ++++++++++
.../sax/StandardInputSourceParserTest.java | 85 ++++++++
.../stream/StandardXMLEventReaderProviderTest.java | 67 ++++++
.../StandardXMLStreamReaderProviderTest.java | 67 ++++++
.../validation/StandardSchemaValidatorTest.java | 68 ++++++
.../standard-document-doctype-entity.xml} | 10 +-
.../test/resources/standard-document-doctype.xml} | 10 +-
.../src/test/resources/standard-document.xml} | 10 +-
...standard-namespace-document-doctype-entity.xml} | 10 +-
.../resources/standard-namespace-document.xml} | 10 +-
.../src/test/resources/standard-schema.xsd} | 12 +-
nifi-commons/pom.xml | 1 +
.../AbstractPolicyBasedAuthorizer.java | 19 +-
.../nifi-evtx-bundle/nifi-evtx-processors/pom.xml | 6 +
.../apache/nifi/processors/evtx/ParseEvtxTest.java | 26 ++-
.../nifi/authorization/AuthorizerFactoryBean.java | 10 +-
.../nifi-framework/nifi-documentation/pom.xml | 5 +
.../nifi/documentation/html/XmlValidator.java | 28 +--
.../nifi-framework/nifi-file-authorizer/pom.xml | 5 +
.../authorization/FileAccessPolicyProvider.java | 23 +-
.../nifi/authorization/FileUserGroupProvider.java | 26 +--
.../nifi/authorization/FlowParserTest.groovy | 66 ------
.../src/test/resources/flow-with-xxe.xml.gz | Bin 794 -> 0 bytes
.../nifi-framework-authorization-providers/pom.xml | 5 +
.../authorization/StandardManagedAuthorizer.java | 15 +-
.../nifi-framework-cluster-protocol/pom.xml | 10 +
.../nifi/cluster/protocol/HeartbeatPayload.java | 11 +-
.../nifi/cluster/protocol/StandardDataFlow.java | 26 +--
.../cluster/protocol/jaxb/JaxbProtocolContext.java | 11 +-
.../nifi-framework-components/pom.xml | 10 +
.../state/config/StateManagerConfiguration.java | 18 +-
.../nifi-framework/nifi-framework-core/pom.xml | 5 +
.../org/apache/nifi/cluster/BulletinsPayload.java | 12 +-
.../serialization/StandardFlowSerializer.java | 17 +-
.../service/ControllerServiceLoader.java | 15 +-
.../nifi/fingerprint/FingerprintFactory.java | 35 ++-
.../persistence/StandardSnippetDeserializer.java | 12 +-
.../nifi/persistence/TemplateDeserializer.java | 11 +-
.../main/java/org/apache/nifi/util/FlowParser.java | 28 ++-
.../nifi/fingerprint/FingerprintFactoryTest.java | 76 ++-----
.../nifi/persistence/TemplateSerializerTest.java | 7 +-
.../nifi-framework/nifi-web/nifi-web-api/pom.xml | 4 +
.../org/apache/nifi/audit/ProcessorAuditor.java | 18 +-
.../apache/nifi/web/api/ProcessGroupResource.java | 8 +-
.../spring/LoginIdentityProviderFactoryBean.java | 6 +-
nifi-nar-bundles/nifi-framework-bundle/pom.xml | 5 +
.../nifi-ranger-bundle/nifi-ranger-plugin/pom.xml | 2 +-
.../authorization/ManagedRangerAuthorizer.java | 18 +-
.../nifi-single-user-iaa-providers/pom.xml | 5 +
.../single/user/SingleUserAuthorizer.java | 10 +-
.../nifi-standard-processors/pom.xml | 5 +
.../nifi/processors/standard/EvaluateXPath.java | 161 +++++---------
.../nifi/processors/standard/EvaluateXQuery.java | 132 ++++--------
.../apache/nifi/processors/standard/SplitXml.java | 58 ++---
.../nifi/processors/standard/TransformXml.java | 10 +-
.../nifi/processors/standard/ValidateXml.java | 65 +++---
.../standard/util/DocumentReaderCallback.java | 15 +-
.../xml/DocumentTypeAllowedDocumentProvider.java | 34 +++
.../processors/standard/TestEvaluateXPath.java | 58 ++---
.../processors/standard/TestEvaluateXQuery.java | 238 ++++++++++-----------
.../nifi-lookup-services/pom.xml | 5 -
.../apache/nifi/lookup/XMLFileLookupService.java | 2 +-
.../CommonsConfigurationLookupService.java | 1 -
.../configuration2}/SafeXMLConfiguration.java | 6 +-
.../nifi/lookup/configuration2}/XXEValidator.java | 2 +-
.../lookup/configuration2}/XXEValidatorTest.java | 3 +-
.../src/test/resources/local_xxe_file.xml | 0
.../src/test/resources/multiline_xxe_file.xml | 0
.../src/test/resources/no_xxe.xml | 0
.../src/test/resources/remote_xxe_file.xml | 0
.../src/test/resources/whitespace_xxe_file.xml | 0
.../nifi-record-serialization-services/pom.xml | 5 +
.../windowsevent/WindowsEventLogRecordReader.java | 18 +-
.../java/org/apache/nifi/xml/XMLRecordReader.java | 13 +-
.../apache/nifi/xml/inference/XmlRecordSource.java | 16 +-
.../nifi-update-attribute-model/pom.xml | 2 +-
.../update/attributes/serde/CriteriaSerDe.java | 12 +-
.../nifi-registry-framework/pom.xml | 5 +
.../authentication/IdentityProviderFactory.java | 6 +-
.../AbstractPolicyBasedAuthorizer.java | 14 +-
.../security/authorization/AuthorizerFactory.java | 13 +-
.../authorization/StandardManagedAuthorizer.java | 14 +-
.../file/FileAccessPolicyProvider.java | 13 +-
.../authorization/file/FileUserGroupProvider.java | 13 +-
.../nifi/registry/security/util/XmlUtils.java | 44 ----
.../service/alias/RegistryUrlAliasService.java | 12 +-
.../service/extension/docs/XmlValidator.java | 26 ++-
.../nifi-registry-ranger-plugin/pom.xml | 7 +
.../nifi/registry/ranger/RangerAuthorizer.java | 21 +-
nifi-system-tests/nifi-system-test-suite/pom.xml | 10 +
.../clustering/JoinClusterWithDifferentFlow.java | 10 +-
nifi-toolkit/nifi-toolkit-flowanalyzer/pom.xml | 5 +
.../toolkit/flowanalyzer/FlowAnalyzerDriver.java | 8 +-
120 files changed, 1998 insertions(+), 1321 deletions(-)
diff --git a/minifi/minifi-bootstrap/pom.xml b/minifi/minifi-bootstrap/pom.xml
index 1bc9ebf059..523ddaf1b4 100644
--- a/minifi/minifi-bootstrap/pom.xml
+++ b/minifi/minifi-bootstrap/pom.xml
@@ -56,6 +56,10 @@ limitations under the License.
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-utils</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ </dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-properties</artifactId>
diff --git a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/util/ConfigTransformer.java b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/util/ConfigTransformer.java
index 1d58e0a870..d3dc8eb382 100644
--- a/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/util/ConfigTransformer.java
+++ b/minifi/minifi-bootstrap/src/main/java/org/apache/nifi/minifi/bootstrap/util/ConfigTransformer.java
@@ -46,15 +46,14 @@ import org.apache.nifi.minifi.commons.schema.common.Schema;
import org.apache.nifi.minifi.commons.schema.common.StringUtil;
import org.apache.nifi.minifi.commons.schema.serialization.SchemaLoader;
import org.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
@@ -148,7 +147,7 @@ public final class ConfigTransformer {
}
}
- protected static void writeFlowXmlFile(ConfigSchema configSchema, OutputStream outputStream) throws TransformerException, ConfigTransformerException, ConfigurationChangeException, IOException {
+ protected static void writeFlowXmlFile(ConfigSchema configSchema, OutputStream outputStream) throws TransformerException, ConfigTransformerException {
final StreamResult streamResult = new StreamResult(outputStream);
// configure the transformer and convert the DOM
@@ -307,14 +306,12 @@ public final class ConfigTransformer {
}
}
- protected static DOMSource createFlowXml(ConfigSchema configSchema) throws IOException, ConfigurationChangeException, ConfigTransformerException {
+ protected static DOMSource createFlowXml(ConfigSchema configSchema) throws ConfigTransformerException {
try {
// create a new, empty document
- final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
- docFactory.setNamespaceAware(true);
-
- final DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
- final Document doc = docBuilder.newDocument();
+ final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
+ documentProvider.setNamespaceAware(true);
+ final Document doc = documentProvider.newDocument();
// populate document with controller state
final Element rootNode = doc.createElement("flowController");
@@ -365,7 +362,7 @@ public final class ConfigTransformer {
}
return new DOMSource(doc);
- } catch (final ParserConfigurationException | DOMException | TransformerFactoryConfigurationError | IllegalArgumentException e) {
+ } catch (final ProcessingException | DOMException | TransformerFactoryConfigurationError | IllegalArgumentException e) {
throw new ConfigTransformerException(e);
} catch (Exception e) {
throw new ConfigTransformerException("Failed to parse the config YAML while writing the top level of the flow xml", e);
diff --git a/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/util/ConfigTransformerTest.java b/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/util/ConfigTransformerTest.java
index bb01784f8b..7ca896c75b 100644
--- a/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/util/ConfigTransformerTest.java
+++ b/minifi/minifi-bootstrap/src/test/java/org/apache/nifi/minifi/bootstrap/util/ConfigTransformerTest.java
@@ -34,6 +34,8 @@ import org.apache.nifi.minifi.commons.schema.common.StringUtil;
import org.apache.nifi.minifi.commons.schema.exception.SchemaLoaderException;
import org.apache.nifi.minifi.commons.schema.serialization.SchemaLoader;
import org.apache.nifi.util.StringUtils;
+import org.apache.nifi.xml.processing.parsers.DocumentProvider;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -42,9 +44,6 @@ import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
@@ -55,7 +54,6 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.StringBufferInputStream;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Collections;
@@ -80,15 +78,14 @@ public class ConfigTransformerTest {
Arrays.asList("processor", "inputPort", "outputPort", "funnel", "processGroup", "remoteProcessGroup", "connection"));
private XPathFactory xPathFactory;
private Element config;
- private DocumentBuilder documentBuilder;
@Rule
final public TemporaryFolder tempOutputFolder = new TemporaryFolder();
@Before
- public void setup() throws ParserConfigurationException {
- documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
- final Document document = documentBuilder.newDocument();
+ public void setup() {
+ final DocumentProvider documentProvider = new StandardDocumentProvider();
+ final Document document = documentProvider.newDocument();
config = document.createElement("config");
xPathFactory = XPathFactory.newInstance();
}
@@ -484,11 +481,11 @@ public class ConfigTransformerTest {
assertTrue(flowXml.exists());
assertTrue(flowXml.canRead());
- String flow = loadFlowXML(new FileInputStream(flowXml));
-
- DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
- DocumentBuilder db = dbf.newDocumentBuilder();
- Document xml = db.parse(new StringBufferInputStream(flow));
+ final DocumentProvider documentProvider = new StandardDocumentProvider();
+ final Document xml;
+ try (final InputStream inputStream = new GZIPInputStream(new FileInputStream(flowXml))) {
+ xml = documentProvider.parse(inputStream);
+ }
XPath xPath = XPathFactory.newInstance().newXPath();
String result = xPath.evaluate("/flowController/rootGroup/processor/property[name = \"SSL Context Service\"]/value/text()", xml);
@@ -504,7 +501,8 @@ public class ConfigTransformerTest {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ConfigTransformer.writeFlowXmlFile(configSchema, outputStream);
- Document document = documentBuilder.parse(new ByteArrayInputStream(outputStream.toByteArray()));
+ final DocumentProvider documentProvider = new StandardDocumentProvider();
+ Document document = documentProvider.parse(new ByteArrayInputStream(outputStream.toByteArray()));
testProcessGroup((Element) xPathFactory.newXPath().evaluate("flowController/rootGroup", document, XPathConstants.NODE), configSchema.getProcessGroupSchema());
testReportingTasks((Element) xPathFactory.newXPath().evaluate("flowController/reportingTasks", document, XPathConstants.NODE), configSchema.getReportingTasksSchema());
@@ -786,17 +784,4 @@ public class ConfigTransformerTest {
}
return bootstrapProperties;
}
-
- public static String loadFlowXML(InputStream compressedData) throws IOException {
- ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
- GZIPInputStream gzipInputStream = new GZIPInputStream(compressedData);
-
- byte[] buffer = new byte[1024];
- int len;
- while ((len = gzipInputStream.read(buffer)) != -1) {
- byteArrayOutputStream.write(buffer, 0, len);
- }
-
- return byteArrayOutputStream.toString();
- }
}
diff --git a/minifi/pom.xml b/minifi/pom.xml
index 1b53c9c52d..73e50de068 100644
--- a/minifi/pom.xml
+++ b/minifi/pom.xml
@@ -385,6 +385,11 @@ limitations under the License.
<artifactId>nifi-security-utils</artifactId>
<version>1.16.1-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-logging-utils</artifactId>
diff --git a/nifi-bootstrap/pom.xml b/nifi-bootstrap/pom.xml
index f88f63cd5e..bd109336ab 100644
--- a/nifi-bootstrap/pom.xml
+++ b/nifi-bootstrap/pom.xml
@@ -45,6 +45,11 @@ language governing permissions and limitations under the License. -->
<artifactId>nifi-security-utils</artifactId>
<version>1.16.1-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-flow-encryptor</artifactId>
diff --git a/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/NotificationServiceManager.java b/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/NotificationServiceManager.java
index e7d524b587..97582fe8c9 100644
--- a/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/NotificationServiceManager.java
+++ b/nifi-bootstrap/src/main/java/org/apache/nifi/bootstrap/NotificationServiceManager.java
@@ -31,18 +31,14 @@ import org.apache.nifi.components.resource.StandardResourceContext;
import org.apache.nifi.components.resource.StandardResourceReferenceFactory;
import org.apache.nifi.parameter.ParameterLookup;
import org.apache.nifi.registry.VariableRegistry;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
@@ -91,27 +87,6 @@ public class NotificationServiceManager {
this.maxAttempts = maxAttempts;
}
- private static DocumentBuilder createSafeDocumentBuilder() throws ParserConfigurationException {
- final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
- docFactory.setNamespaceAware(false);
-
- // These features are used to disable processing external entities in the DocumentBuilderFactory to protect against XXE attacks
- final String DISALLOW_DOCTYPES = "http://apache.org/xml/features/disallow-doctype-decl";
- final String ALLOW_EXTERNAL_GENERAL_ENTITIES = "http://xml.org/sax/features/external-general-entities";
- final String ALLOW_EXTERNAL_PARAM_ENTITIES = "http://xml.org/sax/features/external-parameter-entities";
- final String ALLOW_EXTERNAL_DTD = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
-
- // Disable DTDs and external entities to protect against XXE
- docFactory.setAttribute(DISALLOW_DOCTYPES, true);
- docFactory.setAttribute(ALLOW_EXTERNAL_DTD, false);
- docFactory.setAttribute(ALLOW_EXTERNAL_GENERAL_ENTITIES, false);
- docFactory.setAttribute(ALLOW_EXTERNAL_PARAM_ENTITIES, false);
- docFactory.setXIncludeAware(false);
- docFactory.setExpandEntityReferences(false);
-
- return docFactory.newDocumentBuilder();
- }
-
/**
* Loads the Notification Services from the given XML configuration file.
*
@@ -143,17 +118,14 @@ public class NotificationServiceManager {
*
* @param servicesFile the XML file to load services from.
* @throws IOException if unable to read from the given file
- * @throws ParserConfigurationException if unable to parse the given file as XML properly
- * @throws SAXException if unable to parse the given file properly
*/
- public void loadNotificationServices(final File servicesFile) throws IOException, ParserConfigurationException, SAXException {
- final DocumentBuilder docBuilder = createSafeDocumentBuilder();
-
+ public void loadNotificationServices(final File servicesFile) throws IOException {
final Map<String, ConfiguredNotificationService> serviceMap = new HashMap<>();
try (final InputStream fis = new FileInputStream(servicesFile);
final InputStream in = new BufferedInputStream(fis)) {
- final Document doc = docBuilder.parse(new InputSource(in));
+ final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
+ final Document doc = documentProvider.parse(in);
final List<Element> serviceElements = getChildElementsByTagName(doc.getDocumentElement(), "service");
logger.debug("Found {} service elements", serviceElements.size());
diff --git a/nifi-commons/nifi-security-utils/pom.xml b/nifi-commons/nifi-security-utils/pom.xml
index b939fee380..af1d6176f4 100644
--- a/nifi-commons/nifi-security-utils/pom.xml
+++ b/nifi-commons/nifi-security-utils/pom.xml
@@ -42,11 +42,6 @@
<artifactId>nifi-security-utils-api</artifactId>
<version>1.16.1-SNAPSHOT</version>
</dependency>
- <dependency>
- <groupId>org.apache.nifi</groupId>
- <artifactId>nifi-security-kms</artifactId>
- <version>1.16.1-SNAPSHOT</version>
- </dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
@@ -73,67 +68,6 @@
<artifactId>bcrypt</artifactId>
<version>0.9.0</version>
</dependency>
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-configuration2</artifactId>
- <version>2.7</version>
- <exclusions>
- <exclusion>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>jcl-over-slf4j</artifactId>
- </dependency>
</dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.rat</groupId>
- <artifactId>apache-rat-plugin</artifactId>
- <configuration>
- <excludes combine.children="append">
- <exclude>src/test/resources/xxe_template.xml</exclude>
- </excludes>
- </configuration>
- </plugin>
- </plugins>
- </build>
-
- <profiles>
- <profile>
- <!-- This profile, activating when compiling on Java versions above 1.8, provides configuration changes to
- allow NiFi to be compiled on those JDKs. -->
- <id>jigsaw</id>
- <activation>
- <jdk>(1.8,)</jdk>
- </activation>
- <dependencies>
- <dependency>
- <groupId>jakarta.xml.bind</groupId>
- <artifactId>jakarta.xml.bind-api</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>org.glassfish.jaxb</groupId>
- <artifactId>jaxb-runtime</artifactId>
- <scope>test</scope>
- </dependency>
- <dependency>
- <groupId>com.sun.activation</groupId>
- <artifactId>javax.activation</artifactId>
- </dependency>
- </dependencies>
- </profile>
- </profiles>
-
-
- <scm>
- <tag>nifi-1.16.0-RC3</tag>
- </scm>
</project>
diff --git a/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/xml/XmlUtils.java b/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/xml/XmlUtils.java
deleted file mode 100644
index 0066806b7c..0000000000
--- a/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/xml/XmlUtils.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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.nifi.security.xml;
-
-import java.io.InputStream;
-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 javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamReader;
-import javax.xml.transform.stream.StreamSource;
-import javax.xml.validation.Schema;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-
-public class XmlUtils {
-
- // These features are used to disable processing external entities in the DocumentBuilderFactory to protect against XXE attacks
- private static final String DISALLOW_DOCTYPES = "http://apache.org/xml/features/disallow-doctype-decl";
- private static final String ALLOW_EXTERNAL_GENERAL_ENTITIES = "http://xml.org/sax/features/external-general-entities";
- private static final String ALLOW_EXTERNAL_PARAM_ENTITIES = "http://xml.org/sax/features/external-parameter-entities";
- private static final String ALLOW_EXTERNAL_DTD = "http://apache.org/xml/features/nonvalidating/load-external-dtd";
-
- public static XMLStreamReader createSafeReader(InputStream inputStream) throws XMLStreamException {
- if (inputStream == null) {
- throw new IllegalArgumentException("The provided input stream cannot be null");
- }
- return createSafeReader(new StreamSource(inputStream));
- }
-
- public static XMLStreamReader createSafeReader(StreamSource source) throws XMLStreamException {
- if (source == null) {
- throw new IllegalArgumentException("The provided source cannot be null");
- }
-
- XMLInputFactory xif = XMLInputFactory.newFactory();
- xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
- xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
- return xif.createXMLStreamReader(source);
- }
-
- public static XMLReader createSafeSaxReader(SAXParserFactory saxParserFactory, ContentHandler contentHandler) throws SAXException, ParserConfigurationException {
- if (saxParserFactory == null) {
- throw new IllegalArgumentException("The provided SAX parser factory cannot be null");
- }
-
- if (contentHandler == null) {
- throw new IllegalArgumentException("The provided SAX content handler cannot be null");
- }
-
- SAXParser saxParser = saxParserFactory.newSAXParser();
- XMLReader xmlReader = saxParser.getXMLReader();
- xmlReader.setFeature(DISALLOW_DOCTYPES, true);
- xmlReader.setFeature(ALLOW_EXTERNAL_GENERAL_ENTITIES, false);
- xmlReader.setFeature(ALLOW_EXTERNAL_PARAM_ENTITIES, false);
- xmlReader.setContentHandler(contentHandler);
-
- return xmlReader;
- }
-
- public static DocumentBuilder createSafeDocumentBuilder(Schema schema, boolean isNamespaceAware) throws ParserConfigurationException {
- final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
- docFactory.setSchema(schema);
- docFactory.setNamespaceAware(isNamespaceAware);
-
- // Disable DTDs and external entities to protect against XXE
- docFactory.setAttribute(DISALLOW_DOCTYPES, true);
- docFactory.setAttribute(ALLOW_EXTERNAL_DTD, false);
- docFactory.setAttribute(ALLOW_EXTERNAL_GENERAL_ENTITIES, false);
- docFactory.setAttribute(ALLOW_EXTERNAL_PARAM_ENTITIES, false);
- docFactory.setXIncludeAware(false);
- docFactory.setExpandEntityReferences(false);
-
- return docFactory.newDocumentBuilder();
- }
-
- public static DocumentBuilder createSafeDocumentBuilder(Schema schema) throws ParserConfigurationException {
- return createSafeDocumentBuilder(schema, true);
- }
-
- public static DocumentBuilder createSafeDocumentBuilder(boolean isNamespaceAware) throws ParserConfigurationException {
- return createSafeDocumentBuilder(null, isNamespaceAware);
- }
-}
diff --git a/nifi-commons/nifi-security-utils/src/test/groovy/org/apache/nifi/security/xml/XmlUtilsTest.groovy b/nifi-commons/nifi-security-utils/src/test/groovy/org/apache/nifi/security/xml/XmlUtilsTest.groovy
deleted file mode 100644
index fb12bfec00..0000000000
--- a/nifi-commons/nifi-security-utils/src/test/groovy/org/apache/nifi/security/xml/XmlUtilsTest.groovy
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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.nifi.security.xml
-
-import org.junit.jupiter.api.BeforeAll
-import org.junit.jupiter.api.Test
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-import org.xml.sax.SAXParseException
-
-import javax.xml.bind.JAXBContext
-import javax.xml.bind.UnmarshalException
-import javax.xml.bind.Unmarshaller
-import javax.xml.bind.annotation.XmlAccessType
-import javax.xml.bind.annotation.XmlAccessorType
-import javax.xml.bind.annotation.XmlAttribute
-import javax.xml.bind.annotation.XmlRootElement
-import javax.xml.parsers.DocumentBuilder
-import javax.xml.stream.XMLStreamReader
-
-import static groovy.test.GroovyAssert.shouldFail
-
-class XmlUtilsTest {
- private static final Logger logger = LoggerFactory.getLogger(XmlUtilsTest.class)
-
- @BeforeAll
- static void setUpOnce() throws Exception {
- logger.metaClass.methodMissing = { String name, args ->
- logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
- }
- }
-
- @Test
- void testShouldHandleXXEInUnmarshal() {
- // Arrange
- final String XXE_TEMPLATE_FILEPATH = "src/test/resources/local_xxe_file.xml"
- InputStream templateStream = new File(XXE_TEMPLATE_FILEPATH).newInputStream()
-
- JAXBContext context = JAXBContext.newInstance(XmlObject.class)
-
- // Act
- def msg = shouldFail(UnmarshalException) {
- Unmarshaller unmarshaller = context.createUnmarshaller()
- XMLStreamReader xsr = XmlUtils.createSafeReader(templateStream)
- def parsed = unmarshaller.unmarshal(xsr, XmlObject.class)
- logger.info("Unmarshalled ${parsed.toString()}")
- }
-
- // Assert
- logger.expected(msg)
- assert msg =~ "XMLStreamException: ParseError "
- }
-
- @Test
- void testShouldHandleXXEInDocumentBuilder() {
- // Arrange
- final String XXE_TEMPLATE_FILEPATH = "src/test/resources/local_xxe_file.xml"
- DocumentBuilder documentBuilder = XmlUtils.createSafeDocumentBuilder(null)
-
- // Act
- def msg = shouldFail(SAXParseException) {
- def parsedFlow = documentBuilder.parse(new File(XXE_TEMPLATE_FILEPATH))
- logger.info("Parsed ${parsedFlow.toString()}")
- }
-
- // Assert
- logger.expected(msg)
- assert msg =~ "SAXParseException.*DOCTYPE"
- }
-}
-
-@XmlAccessorType(XmlAccessType.NONE)
-@XmlRootElement(name = "object")
-class XmlObject {
- @XmlAttribute
- String name
-
- @XmlAttribute
- String description
-
- @XmlAttribute
- String groupId
-
- @XmlAttribute
- String timestamp
-}
diff --git a/nifi-commons/nifi-single-user-utils/pom.xml b/nifi-commons/nifi-single-user-utils/pom.xml
index 64901e3203..3755df2654 100644
--- a/nifi-commons/nifi-single-user-utils/pom.xml
+++ b/nifi-commons/nifi-single-user-utils/pom.xml
@@ -22,6 +22,11 @@
</parent>
<artifactId>nifi-single-user-utils</artifactId>
<dependencies>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>at.favre.lib</groupId>
<artifactId>bcrypt</artifactId>
diff --git a/nifi-commons/nifi-single-user-utils/src/main/java/org/apache/nifi/authentication/single/user/writer/StandardLoginCredentialsWriter.java b/nifi-commons/nifi-single-user-utils/src/main/java/org/apache/nifi/authentication/single/user/writer/StandardLoginCredentialsWriter.java
index 520b330d2b..c834252fdf 100644
--- a/nifi-commons/nifi-single-user-utils/src/main/java/org/apache/nifi/authentication/single/user/writer/StandardLoginCredentialsWriter.java
+++ b/nifi-commons/nifi-single-user-utils/src/main/java/org/apache/nifi/authentication/single/user/writer/StandardLoginCredentialsWriter.java
@@ -17,11 +17,12 @@
package org.apache.nifi.authentication.single.user.writer;
import org.apache.nifi.authentication.single.user.SingleUserCredentials;
+import org.apache.nifi.xml.processing.stream.StandardXMLEventReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLEventReaderProvider;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
-import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
@@ -29,6 +30,7 @@ import javax.xml.stream.events.Characters;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
+import javax.xml.transform.stream.StreamSource;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
@@ -199,10 +201,8 @@ public class StandardLoginCredentialsWriter implements LoginCredentialsWriter {
return outputFactory.createXMLEventWriter(outputStream);
}
- private XMLEventReader getProvidersReader(final InputStream inputStream) throws XMLStreamException {
- final XMLInputFactory inputFactory = XMLInputFactory.newFactory();
- inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
- inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
- return inputFactory.createXMLEventReader(inputStream);
+ private XMLEventReader getProvidersReader(final InputStream inputStream) {
+ final XMLEventReaderProvider readerProvider = new StandardXMLEventReaderProvider();
+ return readerProvider.getEventReader(new StreamSource(inputStream));
}
}
diff --git a/nifi-commons/nifi-site-to-site-client/pom.xml b/nifi-commons/nifi-site-to-site-client/pom.xml
index 8209826d23..2019305a34 100644
--- a/nifi-commons/nifi-site-to-site-client/pom.xml
+++ b/nifi-commons/nifi-site-to-site-client/pom.xml
@@ -51,6 +51,11 @@
<artifactId>nifi-security-utils</artifactId>
<version>1.16.1-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
diff --git a/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/cluster/ClusterNodeInformation.java b/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/cluster/ClusterNodeInformation.java
index 5a0264e4d4..6963701cf2 100644
--- a/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/cluster/ClusterNodeInformation.java
+++ b/nifi-commons/nifi-site-to-site-client/src/main/java/org/apache/nifi/remote/cluster/ClusterNodeInformation.java
@@ -25,9 +25,12 @@ import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
-import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
-import org.apache.nifi.security.xml.XmlUtils;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLStreamReaderProvider;
@XmlRootElement
public class ClusterNodeInformation {
@@ -65,9 +68,10 @@ public class ClusterNodeInformation {
public static ClusterNodeInformation unmarshal(final InputStream is) throws JAXBException {
try {
final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
- final XMLStreamReader xsr = XmlUtils.createSafeReader(is);
+ final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
+ final XMLStreamReader xsr = provider.getStreamReader(new StreamSource(is));
return (ClusterNodeInformation) unmarshaller.unmarshal(xsr);
- } catch (XMLStreamException e) {
+ } catch (final ProcessingException e) {
throw new JAXBException("Error unmarshalling the cluster node information", e);
}
}
diff --git a/nifi-commons/nifi-xml-processing/pom.xml b/nifi-commons/nifi-xml-processing/pom.xml
new file mode 100644
index 0000000000..6eb9ba88c0
--- /dev/null
+++ b/nifi-commons/nifi-xml-processing/pom.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0"?>
+<!--
+ 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.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-commons</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>nifi-xml-processing</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ <packaging>jar</packaging>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.github.spotbugs</groupId>
+ <artifactId>spotbugs-maven-plugin</artifactId>
+ <version>4.6.0.0</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <effort>Max</effort>
+ <threshold>low</threshold>
+ <failOnError>true</failOnError>
+ <plugins>
+ <plugin>
+ <groupId>com.h3xstream.findsecbugs</groupId>
+ <artifactId>findsecbugs-plugin</artifactId>
+ <version>1.12.0</version>
+ </plugin>
+ </plugins>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+</project>
diff --git a/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/ProcessingException.java b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/ProcessingException.java
new file mode 100644
index 0000000000..d0d186d710
--- /dev/null
+++ b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/ProcessingException.java
@@ -0,0 +1,32 @@
+/*
+ * 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.nifi.xml.processing;
+
+/**
+ * General Exception for XML processing problems
+ */
+public class ProcessingException extends RuntimeException {
+ /**
+ * Processing Exception with message and cause for tracing
+ *
+ * @param message Error Message
+ * @param cause Throwable cause for tracing
+ */
+ public ProcessingException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/ProcessingFeature.java b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/ProcessingFeature.java
new file mode 100644
index 0000000000..ee4946cd64
--- /dev/null
+++ b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/ProcessingFeature.java
@@ -0,0 +1,53 @@
+/*
+ * 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.nifi.xml.processing;
+
+import javax.xml.XMLConstants;
+
+/**
+ * XML Processing Features
+ */
+public enum ProcessingFeature {
+ /** Secure Processing */
+ SECURE_PROCESSING(XMLConstants.FEATURE_SECURE_PROCESSING, true),
+
+ /** SAX Namespaces */
+ SAX_NAMESPACES("http://xml.org/sax/features/namespaces", true),
+
+ /** SAX Namespace Prefixes */
+ SAX_NAMESPACE_PREFIXES("http://xml.org/sax/features/namespace-prefixes", true),
+
+ /** Disallow Document Type Declaration */
+ DISALLOW_DOCTYPE_DECL("http://apache.org/xml/features/disallow-doctype-decl", true);
+
+ private final String feature;
+
+ private final boolean enabled;
+
+ ProcessingFeature(final String feature, final boolean enabled) {
+ this.feature = feature;
+ this.enabled = enabled;
+ }
+
+ public String getFeature() {
+ return feature;
+ }
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+}
diff --git a/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/parsers/DocumentProvider.java b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/parsers/DocumentProvider.java
new file mode 100644
index 0000000000..20c9ba5369
--- /dev/null
+++ b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/parsers/DocumentProvider.java
@@ -0,0 +1,41 @@
+/*
+ * 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.nifi.xml.processing.parsers;
+
+import org.w3c.dom.Document;
+
+import java.io.InputStream;
+
+/**
+ * Provider for instances of Document Object Model
+ */
+public interface DocumentProvider {
+ /**
+ * Create new Document
+ *
+ * @return Document
+ */
+ Document newDocument();
+
+ /**
+ * Parse InputStream to Document
+ *
+ * @param inputStream InputStream to be parsed
+ * @return Document parsed from stream
+ */
+ Document parse(InputStream inputStream);
+}
diff --git a/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/parsers/StandardDocumentProvider.java b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/parsers/StandardDocumentProvider.java
new file mode 100644
index 0000000000..e457fdc5a5
--- /dev/null
+++ b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/parsers/StandardDocumentProvider.java
@@ -0,0 +1,126 @@
+/*
+ * 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.nifi.xml.processing.parsers;
+
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.ProcessingFeature;
+import org.w3c.dom.Document;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.validation.Schema;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Objects;
+
+/**
+ * Standard implementation of Document Provider with secure processing enabled
+ */
+public class StandardDocumentProvider implements DocumentProvider {
+ private boolean namespaceAware;
+
+ private Schema schema;
+
+ private ErrorHandler errorHandler;
+
+ /**
+ * Set Error Handler
+ *
+ * @param errorHandler Error Handler
+ */
+ public void setErrorHandler(final ErrorHandler errorHandler) {
+ this.errorHandler = errorHandler;
+ }
+
+ /**
+ * Set Namespace Aware status on DocumentBuilderFactory
+ *
+ * @param namespaceAware Namespace Awareness
+ */
+ public void setNamespaceAware(final boolean namespaceAware) {
+ this.namespaceAware = namespaceAware;
+ }
+
+ /**
+ * Set Namespace Aware status on DocumentBuilderFactory
+ *
+ * @param schema Schema for validation or null to disable validation
+ */
+ public void setSchema(final Schema schema) {
+ this.schema = schema;
+ }
+
+ @Override
+ public Document newDocument() {
+ final DocumentBuilderFactory documentBuilderFactory = getDocumentBuilderFactory();
+
+ try {
+ documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, ProcessingFeature.SECURE_PROCESSING.isEnabled());
+ documentBuilderFactory.setFeature(ProcessingFeature.DISALLOW_DOCTYPE_DECL.getFeature(), ProcessingFeature.DISALLOW_DOCTYPE_DECL.isEnabled());
+
+ final DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+ documentBuilder.setErrorHandler(errorHandler);
+
+ return documentBuilder.newDocument();
+ } catch (final ParserConfigurationException e) {
+ throw new ProcessingException("Configuration failed", e);
+ }
+ }
+
+ /**
+ * Build and return DocumentBuilder
+ *
+ * @return DocumentBuilder configured using provided properties
+ */
+ @Override
+ public Document parse(final InputStream inputStream) {
+ Objects.requireNonNull(inputStream, "InputStream required");
+ final DocumentBuilderFactory documentBuilderFactory = getDocumentBuilderFactory();
+
+ try {
+ documentBuilderFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, ProcessingFeature.SECURE_PROCESSING.isEnabled());
+ documentBuilderFactory.setFeature(ProcessingFeature.DISALLOW_DOCTYPE_DECL.getFeature(), isDisallowDocumentTypeDeclaration());
+
+ final DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
+ documentBuilder.setErrorHandler(errorHandler);
+
+ return documentBuilder.parse(inputStream);
+ } catch (final ParserConfigurationException|SAXException|IOException e) {
+ throw new ProcessingException("Parsing failed", e);
+ }
+ }
+
+ protected boolean isDisallowDocumentTypeDeclaration() {
+ return ProcessingFeature.DISALLOW_DOCTYPE_DECL.isEnabled();
+ }
+
+ private DocumentBuilderFactory getDocumentBuilderFactory() {
+ final DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
+
+ documentBuilderFactory.setSchema(schema);
+ documentBuilderFactory.setNamespaceAware(namespaceAware);
+
+ documentBuilderFactory.setXIncludeAware(false);
+ documentBuilderFactory.setExpandEntityReferences(false);
+
+ return documentBuilderFactory;
+ }
+}
diff --git a/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/sax/InputSourceParser.java b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/sax/InputSourceParser.java
new file mode 100644
index 0000000000..bb50dc7ced
--- /dev/null
+++ b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/sax/InputSourceParser.java
@@ -0,0 +1,33 @@
+/*
+ * 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.nifi.xml.processing.sax;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.InputSource;
+
+/**
+ * SAX Input Source Parser
+ */
+public interface InputSourceParser {
+ /**
+ * Parse Input Source using Content Handler
+ *
+ * @param inputSource Input Source to be parsed
+ * @param contentHandler Content Handler used during parsing
+ */
+ void parse(InputSource inputSource, ContentHandler contentHandler);
+}
diff --git a/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/sax/StandardInputSourceParser.java b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/sax/StandardInputSourceParser.java
new file mode 100644
index 0000000000..14f7b31ed6
--- /dev/null
+++ b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/sax/StandardInputSourceParser.java
@@ -0,0 +1,90 @@
+/*
+ * 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.nifi.xml.processing.sax;
+
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.ProcessingFeature;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * Standard implementation of Input Source Parser with secure processing enabled
+ */
+public class StandardInputSourceParser implements InputSourceParser {
+ private boolean namespaceAware;
+
+ /**
+ * Set Namespace Aware status on SAXParserFactory
+ *
+ * @param namespaceAware Namespace Aware status
+ */
+ public void setNamespaceAware(final boolean namespaceAware) {
+ this.namespaceAware = namespaceAware;
+ }
+
+ /**
+ * Parse Input Source using Content Handler
+ *
+ * @param inputSource Input Source to be parsed
+ * @param contentHandler Content Handler used during parsing
+ */
+ @Override
+ public void parse(final InputSource inputSource, final ContentHandler contentHandler) {
+ Objects.requireNonNull(inputSource, "InputSource required");
+ Objects.requireNonNull(contentHandler, "ContentHandler required");
+
+ try {
+ parseInputSource(inputSource, contentHandler);
+ } catch (final ParserConfigurationException|SAXException e) {
+ throw new ProcessingException("Parsing failed", e);
+ }
+ }
+
+ private void parseInputSource(final InputSource inputSource, final ContentHandler contentHandler) throws ParserConfigurationException, SAXException {
+ final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
+ saxParserFactory.setNamespaceAware(namespaceAware);
+ saxParserFactory.setXIncludeAware(false);
+
+ saxParserFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, ProcessingFeature.SECURE_PROCESSING.isEnabled());
+ saxParserFactory.setFeature(ProcessingFeature.DISALLOW_DOCTYPE_DECL.getFeature(), ProcessingFeature.DISALLOW_DOCTYPE_DECL.isEnabled());
+
+ if (namespaceAware) {
+ saxParserFactory.setFeature(ProcessingFeature.SAX_NAMESPACES.getFeature(), ProcessingFeature.SAX_NAMESPACES.isEnabled());
+ saxParserFactory.setFeature(ProcessingFeature.SAX_NAMESPACE_PREFIXES.getFeature(), ProcessingFeature.SAX_NAMESPACE_PREFIXES.isEnabled());
+ }
+
+ final SAXParser parser = saxParserFactory.newSAXParser();
+
+ final XMLReader reader = parser.getXMLReader();
+ reader.setContentHandler(contentHandler);
+
+ try {
+ reader.parse(inputSource);
+ } catch (final IOException e) {
+ throw new ProcessingException("Parsing failed", e);
+ }
+ }
+}
diff --git a/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/stream/StandardXMLEventReaderProvider.java b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/stream/StandardXMLEventReaderProvider.java
new file mode 100644
index 0000000000..dbfcb282fe
--- /dev/null
+++ b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/stream/StandardXMLEventReaderProvider.java
@@ -0,0 +1,51 @@
+/*
+ * 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.nifi.xml.processing.stream;
+
+import org.apache.nifi.xml.processing.ProcessingException;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.transform.stream.StreamSource;
+import java.util.Objects;
+
+/**
+ * Standard implementation of XMLStreamReader provider with secure processing enabled
+ */
+public class StandardXMLEventReaderProvider implements XMLEventReaderProvider {
+ /**
+ * Get XML Event Reader
+ *
+ * @param streamSource Stream Source for Reader
+ * @return Configured XML Event Reader
+ */
+ @Override
+ public XMLEventReader getEventReader(final StreamSource streamSource) {
+ Objects.requireNonNull(streamSource, "StreamSource required");
+
+ final XMLInputFactory inputFactory = XMLInputFactory.newFactory();
+ inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
+ inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
+
+ try {
+ return inputFactory.createXMLEventReader(streamSource);
+ } catch (final XMLStreamException e) {
+ throw new ProcessingException("Reader creation failed", e);
+ }
+ }
+}
diff --git a/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/stream/StandardXMLStreamReaderProvider.java b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/stream/StandardXMLStreamReaderProvider.java
new file mode 100644
index 0000000000..fdefd693a2
--- /dev/null
+++ b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/stream/StandardXMLStreamReaderProvider.java
@@ -0,0 +1,51 @@
+/*
+ * 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.nifi.xml.processing.stream;
+
+import org.apache.nifi.xml.processing.ProcessingException;
+
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.stream.StreamSource;
+import java.util.Objects;
+
+/**
+ * Standard implementation of XMLStreamReader provider with secure processing enabled
+ */
+public class StandardXMLStreamReaderProvider implements XMLStreamReaderProvider {
+ /**
+ * Get XML Stream Reader with external entities disabled
+ *
+ * @param streamSource Stream Source for Reader
+ * @return Configured XML Stream Reader
+ */
+ @Override
+ public XMLStreamReader getStreamReader(final StreamSource streamSource) {
+ Objects.requireNonNull(streamSource, "StreamSource required");
+
+ final XMLInputFactory inputFactory = XMLInputFactory.newFactory();
+ inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
+ inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
+
+ try {
+ return inputFactory.createXMLStreamReader(streamSource);
+ } catch (final XMLStreamException e) {
+ throw new ProcessingException("Reader creation failed", e);
+ }
+ }
+}
diff --git a/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/stream/XMLEventReaderProvider.java b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/stream/XMLEventReaderProvider.java
new file mode 100644
index 0000000000..a67fe66c70
--- /dev/null
+++ b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/stream/XMLEventReaderProvider.java
@@ -0,0 +1,33 @@
+/*
+ * 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.nifi.xml.processing.stream;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.transform.stream.StreamSource;
+
+/**
+ * Provider for instances of XMLEventReader
+ */
+public interface XMLEventReaderProvider {
+ /**
+ * Get XML Event Reader
+ *
+ * @param streamSource Stream Source for Reader
+ * @return Configured XML Event Reader
+ */
+ XMLEventReader getEventReader(StreamSource streamSource);
+}
diff --git a/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/stream/XMLStreamReaderProvider.java b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/stream/XMLStreamReaderProvider.java
new file mode 100644
index 0000000000..fe1deac028
--- /dev/null
+++ b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/stream/XMLStreamReaderProvider.java
@@ -0,0 +1,33 @@
+/*
+ * 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.nifi.xml.processing.stream;
+
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.stream.StreamSource;
+
+/**
+ * Provider for instances of XMLStreamReader
+ */
+public interface XMLStreamReaderProvider {
+ /**
+ * Get XML Stream Reader
+ *
+ * @param streamSource Stream Source for Reader
+ * @return Configured XML Stream Reader
+ */
+ XMLStreamReader getStreamReader(StreamSource streamSource);
+}
diff --git a/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/validation/SchemaValidator.java b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/validation/SchemaValidator.java
new file mode 100644
index 0000000000..a8800debd6
--- /dev/null
+++ b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/validation/SchemaValidator.java
@@ -0,0 +1,33 @@
+/*
+ * 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.nifi.xml.processing.validation;
+
+import javax.xml.transform.Source;
+import javax.xml.validation.Schema;
+
+/**
+ * XML Schema Validator
+ */
+public interface SchemaValidator {
+ /**
+ * Validate Source using Schema
+ *
+ * @param schema Schema source for Validator
+ * @param source Source to be validated
+ */
+ void validate(Schema schema, Source source);
+}
diff --git a/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/validation/StandardSchemaValidator.java b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/validation/StandardSchemaValidator.java
new file mode 100644
index 0000000000..940d7f8cea
--- /dev/null
+++ b/nifi-commons/nifi-xml-processing/src/main/java/org/apache/nifi/xml/processing/validation/StandardSchemaValidator.java
@@ -0,0 +1,59 @@
+/*
+ * 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.nifi.xml.processing.validation;
+
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.ProcessingFeature;
+import org.xml.sax.SAXException;
+
+import javax.xml.XMLConstants;
+import javax.xml.transform.Source;
+import javax.xml.validation.Schema;
+import javax.xml.validation.Validator;
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * Standard implementation of XML Schema Validator with secure processing enabled
+ */
+public class StandardSchemaValidator implements SchemaValidator {
+ /**
+ * Validate Source using Schema
+ *
+ * @param schema Schema source for Validator
+ * @param source Source to be validated
+ */
+ @Override
+ public void validate(final Schema schema, final Source source) {
+ Objects.requireNonNull(schema, "Schema required");
+ Objects.requireNonNull(source, "Source required");
+
+ final Validator validator = schema.newValidator();
+
+ try {
+ validator.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, ProcessingFeature.SECURE_PROCESSING.isEnabled());
+ } catch (final SAXException e) {
+ throw new ProcessingException("Validator configuration failed", e);
+ }
+
+ try {
+ validator.validate(source);
+ } catch (final SAXException|IOException e) {
+ throw new ProcessingException("Validation failed", e);
+ }
+ }
+}
diff --git a/nifi-commons/nifi-xml-processing/src/test/java/org/apache/nifi/xml/processing/ResourceProvider.java b/nifi-commons/nifi-xml-processing/src/test/java/org/apache/nifi/xml/processing/ResourceProvider.java
new file mode 100644
index 0000000000..223165c926
--- /dev/null
+++ b/nifi-commons/nifi-xml-processing/src/test/java/org/apache/nifi/xml/processing/ResourceProvider.java
@@ -0,0 +1,65 @@
+/*
+ * 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.nifi.xml.processing;
+
+import java.io.InputStream;
+
+public class ResourceProvider {
+ private static final String STANDARD_DOCUMENT_DOCTYPE_ENTITY = "/standard-document-doctype-entity.xml";
+
+ private static final String STANDARD_DOCUMENT_DOCTYPE = "/standard-document-doctype.xml";
+
+ private static final String STANDARD_DOCUMENT = "/standard-document.xml";
+
+ private static final String STANDARD_NAMESPACE_DOCUMENT = "/standard-namespace-document.xml";
+
+ private static final String STANDARD_NAMESPACE_DOCUMENT_DOCTYPE_ENTITY = "/standard-namespace-document-doctype-entity.xml";
+
+ private static final String STANDARD_SCHEMA = "/standard-schema.xsd";
+
+ public static InputStream getStandardDocument() {
+ return getResource(STANDARD_DOCUMENT);
+ }
+
+ public static InputStream getStandardDocumentDocTypeEntity() {
+ return getResource(STANDARD_DOCUMENT_DOCTYPE_ENTITY);
+ }
+
+ public static InputStream getStandardDocumentDocType() {
+ return getResource(STANDARD_DOCUMENT_DOCTYPE);
+ }
+
+ public static InputStream getStandardNamespaceDocument() {
+ return getResource(STANDARD_NAMESPACE_DOCUMENT);
+ }
+
+ public static InputStream getStandardNamespaceDocumentDocTypeEntity() {
+ return getResource(STANDARD_NAMESPACE_DOCUMENT_DOCTYPE_ENTITY);
+ }
+
+ public static InputStream getStandardSchema() {
+ return getResource(STANDARD_SCHEMA);
+ }
+
+ private static InputStream getResource(final String path) {
+ final InputStream resource = ResourceProvider.class.getResourceAsStream(path);
+ if (resource == null) {
+ throw new IllegalStateException(String.format("Resource [%s] not found", path));
+ }
+ return resource;
+ }
+}
diff --git a/nifi-commons/nifi-xml-processing/src/test/java/org/apache/nifi/xml/processing/parsers/StandardDocumentProviderTest.java b/nifi-commons/nifi-xml-processing/src/test/java/org/apache/nifi/xml/processing/parsers/StandardDocumentProviderTest.java
new file mode 100644
index 0000000000..15d32f9a1e
--- /dev/null
+++ b/nifi-commons/nifi-xml-processing/src/test/java/org/apache/nifi/xml/processing/parsers/StandardDocumentProviderTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.nifi.xml.processing.parsers;
+
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.ResourceProvider;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.w3c.dom.Document;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXParseException;
+
+import javax.xml.validation.Schema;
+import javax.xml.validation.ValidatorHandler;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class StandardDocumentProviderTest {
+ @Mock
+ Schema schema;
+
+ @Mock
+ ValidatorHandler validatorHandler;
+
+ @Mock
+ ErrorHandler errorHandler;
+
+ @Test
+ void testNewDocument() {
+ final StandardDocumentProvider provider = new StandardDocumentProvider();
+
+ final Document document = provider.newDocument();
+
+ assertNotNull(document);
+ }
+
+ @Test
+ void testParseStandard() throws IOException {
+ final StandardDocumentProvider provider = new StandardDocumentProvider();
+
+ try (final InputStream inputStream = ResourceProvider.getStandardDocument()) {
+ final Document document = provider.parse(inputStream);
+ assertNotNull(document);
+ }
+ }
+
+ @Test
+ void testParseDocumentTypeDeclarationException() throws IOException {
+ final StandardDocumentProvider provider = new StandardDocumentProvider();
+
+ try (final InputStream inputStream = ResourceProvider.getStandardDocumentDocType()) {
+ assertParsingException(inputStream, provider);
+ }
+ }
+
+ @Test
+ void testParseExternalEntityException() throws IOException {
+ final StandardDocumentProvider provider = new StandardDocumentProvider();
+
+ assertParsingException(provider);
+ }
+
+ @Test
+ void testParseNamespaceAwareSchemaConfiguredExternalEntityException() throws IOException {
+ when(schema.newValidatorHandler()).thenReturn(validatorHandler);
+
+ final StandardDocumentProvider provider = new StandardDocumentProvider();
+ provider.setNamespaceAware(true);
+ provider.setSchema(schema);
+ provider.setErrorHandler(errorHandler);
+
+ assertParsingException(provider);
+ }
+
+ private void assertParsingException(final StandardDocumentProvider provider) throws IOException {
+ try (final InputStream inputStream = ResourceProvider.getStandardDocumentDocTypeEntity()) {
+ assertParsingException(inputStream, provider);
+ }
+ }
+
+ private void assertParsingException(final InputStream inputStream, final StandardDocumentProvider provider) {
+ final ProcessingException processingException = assertThrows(ProcessingException.class, () -> provider.parse(inputStream));
+ assertInstanceOf(SAXParseException.class, processingException.getCause());
+ }
+}
diff --git a/nifi-commons/nifi-xml-processing/src/test/java/org/apache/nifi/xml/processing/sax/StandardInputSourceParserTest.java b/nifi-commons/nifi-xml-processing/src/test/java/org/apache/nifi/xml/processing/sax/StandardInputSourceParserTest.java
new file mode 100644
index 0000000000..74d8277fcf
--- /dev/null
+++ b/nifi-commons/nifi-xml-processing/src/test/java/org/apache/nifi/xml/processing/sax/StandardInputSourceParserTest.java
@@ -0,0 +1,85 @@
+/*
+ * 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.nifi.xml.processing.sax;
+
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.ResourceProvider;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+@ExtendWith(MockitoExtension.class)
+public class StandardInputSourceParserTest {
+ @Mock
+ ContentHandler contentHandler;
+
+ @Test
+ void testParseStandard() throws IOException {
+ final StandardInputSourceParser parser = new StandardInputSourceParser();
+
+ try (final InputStream inputStream = ResourceProvider.getStandardDocument()) {
+ parser.parse(new InputSource(inputStream), contentHandler);
+ }
+ }
+
+ @Test
+ void testParseDocumentTypeDeclarationException() throws IOException {
+ final StandardInputSourceParser parser = new StandardInputSourceParser();
+
+ try (final InputStream inputStream = ResourceProvider.getStandardDocumentDocType()) {
+ assertParsingException(inputStream, parser);
+ }
+ }
+
+ @Test
+ void testParseExternalEntityException() throws IOException {
+ final StandardInputSourceParser parser = new StandardInputSourceParser();
+
+ assertParsingException(parser);
+ }
+
+ @Test
+ void testParseNamespaceAwareExternalEntityException() throws IOException {
+ final StandardInputSourceParser parser = new StandardInputSourceParser();
+
+ parser.setNamespaceAware(true);
+
+ assertParsingException(parser);
+ }
+
+ private void assertParsingException(final StandardInputSourceParser parser) throws IOException {
+ try (final InputStream inputStream = ResourceProvider.getStandardDocumentDocTypeEntity()) {
+ assertParsingException(inputStream, parser);
+ }
+ }
+
+ private void assertParsingException(final InputStream inputStream, final StandardInputSourceParser parser) {
+ final ProcessingException processingException = assertThrows(ProcessingException.class, () -> parser.parse(new InputSource(inputStream), new DefaultHandler()));
+ assertInstanceOf(SAXParseException.class, processingException.getCause());
+ }
+}
diff --git a/nifi-commons/nifi-xml-processing/src/test/java/org/apache/nifi/xml/processing/stream/StandardXMLEventReaderProviderTest.java b/nifi-commons/nifi-xml-processing/src/test/java/org/apache/nifi/xml/processing/stream/StandardXMLEventReaderProviderTest.java
new file mode 100644
index 0000000000..32753a0a9a
--- /dev/null
+++ b/nifi-commons/nifi-xml-processing/src/test/java/org/apache/nifi/xml/processing/stream/StandardXMLEventReaderProviderTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.nifi.xml.processing.stream;
+
+import org.apache.nifi.xml.processing.ResourceProvider;
+import org.junit.jupiter.api.Test;
+
+import javax.xml.stream.XMLEventReader;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.transform.stream.StreamSource;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+public class StandardXMLEventReaderProviderTest {
+ @Test
+ void testGetEventReaderStandard() throws IOException, XMLStreamException {
+ final StandardXMLEventReaderProvider provider = new StandardXMLEventReaderProvider();
+
+ try (final InputStream inputStream = ResourceProvider.getStandardDocument()) {
+ final XMLEventReader reader = provider.getEventReader(new StreamSource(inputStream));
+ processReader(reader);
+ }
+ }
+
+ @Test
+ void testGetEventReaderStandardDocumentTypeDeclaration() throws IOException {
+ final StandardXMLEventReaderProvider provider = new StandardXMLEventReaderProvider();
+
+ try (final InputStream inputStream = ResourceProvider.getStandardDocumentDocType()) {
+ final XMLEventReader reader = provider.getEventReader(new StreamSource(inputStream));
+ assertDoesNotThrow(() -> processReader(reader));
+ }
+ }
+
+ @Test
+ void testGetEventReaderStandardExternalEntityException() throws IOException {
+ final StandardXMLEventReaderProvider provider = new StandardXMLEventReaderProvider();
+
+ try (final InputStream inputStream = ResourceProvider.getStandardDocumentDocTypeEntity()) {
+ final XMLEventReader reader = provider.getEventReader(new StreamSource(inputStream));
+ assertThrows(XMLStreamException.class, () -> processReader(reader));
+ }
+ }
+
+ private void processReader(final XMLEventReader reader) throws XMLStreamException {
+ while (reader.hasNext()) {
+ reader.nextEvent();
+ }
+ }
+}
diff --git a/nifi-commons/nifi-xml-processing/src/test/java/org/apache/nifi/xml/processing/stream/StandardXMLStreamReaderProviderTest.java b/nifi-commons/nifi-xml-processing/src/test/java/org/apache/nifi/xml/processing/stream/StandardXMLStreamReaderProviderTest.java
new file mode 100644
index 0000000000..31ffb76522
--- /dev/null
+++ b/nifi-commons/nifi-xml-processing/src/test/java/org/apache/nifi/xml/processing/stream/StandardXMLStreamReaderProviderTest.java
@@ -0,0 +1,67 @@
+/*
+ * 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.nifi.xml.processing.stream;
+
+import org.apache.nifi.xml.processing.ResourceProvider;
+import org.junit.jupiter.api.Test;
+
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.stream.StreamSource;
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+public class StandardXMLStreamReaderProviderTest {
+ @Test
+ void testGetStreamReaderStandard() throws IOException, XMLStreamException {
+ final StandardXMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
+
+ try (final InputStream inputStream = ResourceProvider.getStandardDocument()) {
+ final XMLStreamReader reader = provider.getStreamReader(new StreamSource(inputStream));
+ processReader(reader);
+ }
+ }
+
+ @Test
+ void testGetStreamReaderStandardDocumentTypeDeclaration() throws IOException {
+ final StandardXMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
+
+ try (final InputStream inputStream = ResourceProvider.getStandardDocumentDocType()) {
+ final XMLStreamReader reader = provider.getStreamReader(new StreamSource(inputStream));
+ assertDoesNotThrow(() -> processReader(reader));
+ }
+ }
+
+ @Test
+ void testGetStreamReaderStandardExternalEntityException() throws IOException {
+ final StandardXMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
+
+ try (final InputStream inputStream = ResourceProvider.getStandardDocumentDocTypeEntity()) {
+ final XMLStreamReader reader = provider.getStreamReader(new StreamSource(inputStream));
+ assertThrows(XMLStreamException.class, () -> processReader(reader));
+ }
+ }
+
+ private void processReader(final XMLStreamReader reader) throws XMLStreamException {
+ while (reader.hasNext()) {
+ reader.next();
+ }
+ }
+}
diff --git a/nifi-commons/nifi-xml-processing/src/test/java/org/apache/nifi/xml/processing/validation/StandardSchemaValidatorTest.java b/nifi-commons/nifi-xml-processing/src/test/java/org/apache/nifi/xml/processing/validation/StandardSchemaValidatorTest.java
new file mode 100644
index 0000000000..420bf076a7
--- /dev/null
+++ b/nifi-commons/nifi-xml-processing/src/test/java/org/apache/nifi/xml/processing/validation/StandardSchemaValidatorTest.java
@@ -0,0 +1,68 @@
+/*
+ * 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.nifi.xml.processing.validation;
+
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.ResourceProvider;
+import org.junit.jupiter.api.Test;
+import org.xml.sax.SAXException;
+
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+public class StandardSchemaValidatorTest {
+ private static final String SCHEMA_LANGUAGE = "http://www.w3.org/2001/XMLSchema";
+
+ @Test
+ void testValidate() throws SAXException, IOException {
+ final SchemaFactory schemaFactory = SchemaFactory.newInstance(SCHEMA_LANGUAGE);
+ final Schema schema;
+ try (final InputStream inputStream = ResourceProvider.getStandardSchema()) {
+ schema = schemaFactory.newSchema(new StreamSource(inputStream));
+ }
+
+ final StandardSchemaValidator validator = new StandardSchemaValidator();
+
+ try (final InputStream inputStream = ResourceProvider.getStandardNamespaceDocument()) {
+ validator.validate(schema, new StreamSource(inputStream));
+ }
+ }
+
+ @Test
+ void testValidateExternalEntityException() throws SAXException, IOException {
+ final SchemaFactory schemaFactory = SchemaFactory.newInstance(SCHEMA_LANGUAGE);
+ final Schema schema;
+ try (final InputStream inputStream = ResourceProvider.getStandardSchema()) {
+ schema = schemaFactory.newSchema(new StreamSource(inputStream));
+ }
+
+ final StandardSchemaValidator validator = new StandardSchemaValidator();
+
+ try (final InputStream inputStream = ResourceProvider.getStandardNamespaceDocumentDocTypeEntity()) {
+ final ProcessingException exception = assertThrows(ProcessingException.class, () -> validator.validate(schema, new StreamSource(inputStream)));
+ final Throwable cause = exception.getCause();
+ assertInstanceOf(SAXException.class, cause);
+ }
+ }
+}
diff --git a/nifi-commons/nifi-security-utils/src/test/resources/no_xxe.xml b/nifi-commons/nifi-xml-processing/src/test/resources/standard-document-doctype-entity.xml
similarity index 79%
copy from nifi-commons/nifi-security-utils/src/test/resources/no_xxe.xml
copy to nifi-commons/nifi-xml-processing/src/test/resources/standard-document-doctype-entity.xml
index 56e59ef444..ad770b1073 100644
--- a/nifi-commons/nifi-security-utils/src/test/resources/no_xxe.xml
+++ b/nifi-commons/nifi-xml-processing/src/test/resources/standard-document-doctype-entity.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" ?>
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?><!DOCTYPE standard [<!ENTITY entity SYSTEM 'file:///file-not-found'> %entity;]>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -13,10 +13,4 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<test>
- <properties>
- <property>this is property 1</property>
- <property>this is property 2</property>
- <property value="this is property 3" />
- </properties>
-</test>
+<standard>&entity;</standard>
diff --git a/nifi-commons/nifi-security-utils/src/test/resources/no_xxe.xml b/nifi-commons/nifi-xml-processing/src/test/resources/standard-document-doctype.xml
similarity index 79%
copy from nifi-commons/nifi-security-utils/src/test/resources/no_xxe.xml
copy to nifi-commons/nifi-xml-processing/src/test/resources/standard-document-doctype.xml
index 56e59ef444..d6f400e7c0 100644
--- a/nifi-commons/nifi-security-utils/src/test/resources/no_xxe.xml
+++ b/nifi-commons/nifi-xml-processing/src/test/resources/standard-document-doctype.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" ?>
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?><!DOCTYPE standard>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -13,10 +13,4 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<test>
- <properties>
- <property>this is property 1</property>
- <property>this is property 2</property>
- <property value="this is property 3" />
- </properties>
-</test>
+<standard />
diff --git a/nifi-commons/nifi-security-utils/src/test/resources/no_xxe.xml b/nifi-commons/nifi-xml-processing/src/test/resources/standard-document.xml
similarity index 79%
copy from nifi-commons/nifi-security-utils/src/test/resources/no_xxe.xml
copy to nifi-commons/nifi-xml-processing/src/test/resources/standard-document.xml
index 56e59ef444..72cca017d4 100644
--- a/nifi-commons/nifi-security-utils/src/test/resources/no_xxe.xml
+++ b/nifi-commons/nifi-xml-processing/src/test/resources/standard-document.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" ?>
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -13,10 +13,4 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<test>
- <properties>
- <property>this is property 1</property>
- <property>this is property 2</property>
- <property value="this is property 3" />
- </properties>
-</test>
+<standard />
diff --git a/nifi-commons/nifi-security-utils/src/test/resources/no_xxe.xml b/nifi-commons/nifi-xml-processing/src/test/resources/standard-namespace-document-doctype-entity.xml
similarity index 79%
copy from nifi-commons/nifi-security-utils/src/test/resources/no_xxe.xml
copy to nifi-commons/nifi-xml-processing/src/test/resources/standard-namespace-document-doctype-entity.xml
index 56e59ef444..0b76a7578b 100644
--- a/nifi-commons/nifi-security-utils/src/test/resources/no_xxe.xml
+++ b/nifi-commons/nifi-xml-processing/src/test/resources/standard-namespace-document-doctype-entity.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" ?>
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?><!DOCTYPE standard [<!ENTITY entity SYSTEM 'file:///file-not-found'> %entity;]>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -13,10 +13,4 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<test>
- <properties>
- <property>this is property 1</property>
- <property>this is property 2</property>
- <property value="this is property 3" />
- </properties>
-</test>
+<standard xmlns="urn:standard">&entity;</standard>
diff --git a/nifi-commons/nifi-security-utils/src/test/resources/no_xxe.xml b/nifi-commons/nifi-xml-processing/src/test/resources/standard-namespace-document.xml
similarity index 79%
copy from nifi-commons/nifi-security-utils/src/test/resources/no_xxe.xml
copy to nifi-commons/nifi-xml-processing/src/test/resources/standard-namespace-document.xml
index 56e59ef444..6dc65e802b 100644
--- a/nifi-commons/nifi-security-utils/src/test/resources/no_xxe.xml
+++ b/nifi-commons/nifi-xml-processing/src/test/resources/standard-namespace-document.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" ?>
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -13,10 +13,4 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<test>
- <properties>
- <property>this is property 1</property>
- <property>this is property 2</property>
- <property value="this is property 3" />
- </properties>
-</test>
+<standard xmlns="urn:standard" />
diff --git a/nifi-commons/nifi-security-utils/src/test/resources/no_xxe.xml b/nifi-commons/nifi-xml-processing/src/test/resources/standard-schema.xsd
similarity index 79%
copy from nifi-commons/nifi-security-utils/src/test/resources/no_xxe.xml
copy to nifi-commons/nifi-xml-processing/src/test/resources/standard-schema.xsd
index 56e59ef444..ba850e75f0 100644
--- a/nifi-commons/nifi-security-utils/src/test/resources/no_xxe.xml
+++ b/nifi-commons/nifi-xml-processing/src/test/resources/standard-schema.xsd
@@ -1,4 +1,4 @@
-<?xml version="1.0" ?>
+<?xml version="1.0" encoding="UTF-8" ?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
@@ -13,10 +13,6 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<test>
- <properties>
- <property>this is property 1</property>
- <property>this is property 2</property>
- <property value="this is property 3" />
- </properties>
-</test>
+<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:standard">
+ <xs:element name="standard" />
+</xs:schema>
diff --git a/nifi-commons/pom.xml b/nifi-commons/pom.xml
index 85286c7f0c..7c6ce72ece 100644
--- a/nifi-commons/pom.xml
+++ b/nifi-commons/pom.xml
@@ -64,5 +64,6 @@
<module>nifi-vault-utils</module>
<module>nifi-web-utils</module>
<module>nifi-write-ahead-log</module>
+ <module>nifi-xml-processing</module>
</modules>
</project>
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AbstractPolicyBasedAuthorizer.java b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AbstractPolicyBasedAuthorizer.java
index 6a4fa17057..76b8bc4236 100644
--- a/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AbstractPolicyBasedAuthorizer.java
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/authorization/AbstractPolicyBasedAuthorizer.java
@@ -28,6 +28,7 @@ import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
+import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
@@ -36,6 +37,7 @@ import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
@@ -410,7 +412,7 @@ public abstract class AbstractPolicyBasedAuthorizer implements ManagedAuthorizer
final PoliciesUsersAndGroups policiesUsersAndGroups = parsePoliciesUsersAndGroups(fingerprint);
if (isInheritable(policiesUsersAndGroups)) {
- logger.debug("Inheriting Polciies, Users & Groups");
+ logger.debug("Inheriting Policies, Users & Groups");
inheritPoliciesUsersAndGroups(policiesUsersAndGroups);
} else {
logger.info("Cannot directly inherit Policies, Users & Groups. Will backup existing Policies, Users & Groups, and then replace with proposed configuration");
@@ -427,8 +429,7 @@ public abstract class AbstractPolicyBasedAuthorizer implements ManagedAuthorizer
final byte[] fingerprintBytes = fingerprint.getBytes(StandardCharsets.UTF_8);
try (final ByteArrayInputStream in = new ByteArrayInputStream(fingerprintBytes)) {
- final DocumentBuilder docBuilder = createSafeDocumentBuilder();
- final Document document = docBuilder.parse(in);
+ final Document document = parseFingerprint(in);
final Element rootElement = document.getDocumentElement();
// parse all the users and add them to the current authorizer
@@ -451,14 +452,14 @@ public abstract class AbstractPolicyBasedAuthorizer implements ManagedAuthorizer
Node policyNode = policyNodes.item(i);
accessPolicies.add(parsePolicy((Element) policyNode));
}
- } catch (SAXException | ParserConfigurationException | IOException e) {
+ } catch (final IOException e) {
throw new AuthorizationAccessException("Unable to parse fingerprint", e);
}
return new PoliciesUsersAndGroups(accessPolicies, users, groups);
}
- public static DocumentBuilder createSafeDocumentBuilder() throws ParserConfigurationException {
+ private Document parseFingerprint(final InputStream inputStream) throws IOException {
final DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
docFactory.setSchema(null);
docFactory.setNamespaceAware(true);
@@ -471,7 +472,13 @@ public abstract class AbstractPolicyBasedAuthorizer implements ManagedAuthorizer
docFactory.setXIncludeAware(false);
docFactory.setExpandEntityReferences(false);
- return docFactory.newDocumentBuilder();
+ try {
+ docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
+ final DocumentBuilder documentBuilder = docFactory.newDocumentBuilder();
+ return documentBuilder.parse(inputStream);
+ } catch (final ParserConfigurationException|SAXException e) {
+ throw new IOException("Fingerprint parsing failed", e);
+ }
}
private User parseUser(final Element element) {
diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/pom.xml b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/pom.xml
index a0c79c9f1e..8da2f51c63 100644
--- a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/pom.xml
+++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/pom.xml
@@ -58,6 +58,12 @@
<version>1.16.1-SNAPSHOT</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
diff --git a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/ParseEvtxTest.java b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/ParseEvtxTest.java
index 6e1fd99d35..bae9316189 100644
--- a/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/ParseEvtxTest.java
+++ b/nifi-nar-bundles/nifi-evtx-bundle/nifi-evtx-processors/src/test/java/org/apache/nifi/processors/evtx/ParseEvtxTest.java
@@ -28,10 +28,10 @@ import org.apache.nifi.processors.evtx.parser.FileHeaderFactory;
import org.apache.nifi.processors.evtx.parser.MalformedChunkException;
import org.apache.nifi.processors.evtx.parser.Record;
import org.apache.nifi.processors.evtx.parser.bxml.RootNode;
-import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.util.MockFlowFile;
import org.apache.nifi.util.TestRunner;
import org.apache.nifi.util.TestRunners;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -43,11 +43,8 @@ import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLStreamException;
-import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
@@ -59,8 +56,8 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
@@ -159,7 +156,7 @@ public class ParseEvtxTest {
}
@Test
- public void testProcessFileGranularity() throws IOException, MalformedChunkException, XMLStreamException {
+ public void testProcessFileGranularity() throws IOException, MalformedChunkException {
String basename = "basename";
int chunkNum = 5;
int offset = 10001;
@@ -203,7 +200,7 @@ public class ParseEvtxTest {
}
@Test
- public void testProcessChunkGranularity() throws IOException, MalformedChunkException, XMLStreamException {
+ public void testProcessChunkGranularity() throws IOException, MalformedChunkException {
String basename = "basename";
int chunkNum = 5;
int offset = 10001;
@@ -266,7 +263,7 @@ public class ParseEvtxTest {
}
@Test
- public void testProcess1RecordGranularity() throws IOException, MalformedChunkException, XMLStreamException {
+ public void testProcess1RecordGranularity() throws IOException, MalformedChunkException {
String basename = "basename";
int chunkNum = 5;
int offset = 10001;
@@ -340,7 +337,7 @@ public class ParseEvtxTest {
}
@Test
- public void fileGranularityLifecycleTest() throws IOException, ParserConfigurationException, SAXException {
+ public void fileGranularityLifecycleTest() throws IOException {
String baseName = "testFileName";
String name = baseName + ".evtx";
TestRunner testRunner = TestRunners.newTestRunner(ParseEvtx.class);
@@ -374,7 +371,7 @@ public class ParseEvtxTest {
}
@Test
- public void chunkGranularityLifecycleTest() throws IOException, ParserConfigurationException, SAXException {
+ public void chunkGranularityLifecycleTest() throws IOException {
String baseName = "testFileName";
String name = baseName + ".evtx";
TestRunner testRunner = TestRunners.newTestRunner(ParseEvtx.class);
@@ -406,7 +403,7 @@ public class ParseEvtxTest {
}
@Test
- public void recordGranularityLifecycleTest() throws IOException, ParserConfigurationException, SAXException {
+ public void recordGranularityLifecycleTest() throws IOException {
String baseName = "testFileName";
String name = baseName + ".evtx";
TestRunner testRunner = TestRunners.newTestRunner(ParseEvtx.class);
@@ -471,12 +468,13 @@ public class ParseEvtxTest {
testRunner.assertTransferCount(ParseEvtx.REL_SUCCESS, expectedCount);
}
- private int validateFlowFiles(List<MockFlowFile> successFlowFiles) throws SAXException, IOException, ParserConfigurationException {
+ private int validateFlowFiles(List<MockFlowFile> successFlowFiles) {
assertTrue(successFlowFiles.size() > 0);
int totalSize = 0;
for (MockFlowFile successFlowFile : successFlowFiles) {
// Verify valid XML output
- Document document = XmlUtils.createSafeDocumentBuilder(false).parse(new ByteArrayInputStream(successFlowFile.toByteArray()));
+ final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
+ Document document = documentProvider.parse(successFlowFile.getContentStream());
Element documentElement = document.getDocumentElement();
assertEquals(XmlRootNodeHandler.EVENTS, documentElement.getTagName());
NodeList eventNodes = documentElement.getChildNodes();
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java
index 88bb5ddde3..804c7f2f40 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-authorizer/src/main/java/org/apache/nifi/authorization/AuthorizerFactoryBean.java
@@ -26,9 +26,11 @@ import org.apache.nifi.authorization.generated.Property;
import org.apache.nifi.bundle.Bundle;
import org.apache.nifi.nar.ExtensionManager;
import org.apache.nifi.properties.SensitivePropertyProviderFactoryAware;
-import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.util.file.classloader.ClassLoaderUtils;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLStreamReaderProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
@@ -40,7 +42,6 @@ import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
-import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
@@ -211,12 +212,13 @@ public class AuthorizerFactoryBean extends SensitivePropertyProviderFactoryAware
final Schema schema = schemaFactory.newSchema(Authorizers.class.getResource(AUTHORIZERS_XSD));
// attempt to unmarshal
- final XMLStreamReader xsr = XmlUtils.createSafeReader(new StreamSource(authorizersConfigurationFile));
+ final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
+ final XMLStreamReader xsr = provider.getStreamReader(new StreamSource(authorizersConfigurationFile));
final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
unmarshaller.setSchema(schema);
final JAXBElement<Authorizers> element = unmarshaller.unmarshal(xsr, Authorizers.class);
return element.getValue();
- } catch (XMLStreamException | SAXException | JAXBException e) {
+ } catch (final ProcessingException | SAXException | JAXBException e) {
throw new Exception("Unable to load the authorizer configuration file at: " + authorizersConfigurationFile.getAbsolutePath(), e);
}
} else {
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/pom.xml
index ae37bbe7cf..5838c24f3f 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/pom.xml
@@ -47,6 +47,11 @@
<artifactId>nifi-utils</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/test/java/org/apache/nifi/documentation/html/XmlValidator.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/test/java/org/apache/nifi/documentation/html/XmlValidator.java
index 4cc6b22589..d75c3602a4 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/test/java/org/apache/nifi/documentation/html/XmlValidator.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-documentation/src/test/java/org/apache/nifi/documentation/html/XmlValidator.java
@@ -16,13 +16,13 @@
*/
package org.apache.nifi.documentation.html;
-import java.io.IOException;
-import java.io.StringReader;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.parsers.DocumentProvider;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.junit.Assert;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
/**
* A helper class to validate xml documents.
@@ -30,21 +30,21 @@ import org.xml.sax.SAXException;
*
*/
public class XmlValidator {
+ private static final String DOCTYPE = "<!DOCTYPE html>";
+
+ private static final String EMPTY = "";
/**
- * Asserts a failure if the provided XML is not valid. <strong>This method does
- * not use the "safe" {@link DocumentBuilderFactory} from
- * {@code XmlUtils#createSafeDocumentBuilder(Schema, boolean)} because it checks
- * generated documentation which contains a doctype. </strong>
+ * Asserts a failure if the provided XHTML is not valid
*
* @param xml the XML to validate
*/
public static void assertXmlValid(String xml) {
+ final String html = xml.replace(DOCTYPE, EMPTY);
try {
- final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
- dbf.setNamespaceAware(true);
- dbf.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
- } catch (SAXException | IOException | ParserConfigurationException e) {
+ final DocumentProvider provider = new StandardDocumentProvider();
+ provider.parse(new ByteArrayInputStream(html.getBytes(StandardCharsets.UTF_8)));
+ } catch (final ProcessingException e) {
Assert.fail(e.getMessage());
}
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/pom.xml
index ea21311918..6f13280763 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/pom.xml
@@ -204,6 +204,11 @@
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-security-utils</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-properties</artifactId>
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
index dcd23d7dc3..5be8335a79 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
@@ -30,13 +30,16 @@ import org.apache.nifi.authorization.resource.ResourceType;
import org.apache.nifi.authorization.util.IdentityMapping;
import org.apache.nifi.authorization.util.IdentityMappingUtil;
import org.apache.nifi.components.PropertyValue;
-import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.user.generated.Users;
import org.apache.nifi.util.FlowInfo;
import org.apache.nifi.util.FlowParser;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.util.file.FileUtils;
import org.apache.nifi.web.api.dto.PortDTO;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
+import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLStreamReaderProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
@@ -51,8 +54,6 @@ import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
@@ -501,8 +502,8 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
final byte[] fingerprintBytes = fingerprint.getBytes(StandardCharsets.UTF_8);
try (final ByteArrayInputStream in = new ByteArrayInputStream(fingerprintBytes)) {
- final DocumentBuilder docBuilder = XmlUtils.createSafeDocumentBuilder(false);
- final Document document = docBuilder.parse(in);
+ final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
+ final Document document = documentProvider.parse(in);
final Element rootElement = document.getDocumentElement();
// parse all the policies and add them to the current access policy provider
@@ -511,7 +512,7 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
Node policyNode = policyNodes.item(i);
policies.add(parsePolicy((Element) policyNode));
}
- } catch (SAXException | ParserConfigurationException | IOException e) {
+ } catch (final ProcessingException | IOException e) {
throw new AuthorizationAccessException("Unable to parse fingerprint", e);
}
@@ -631,13 +632,14 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
private Authorizations unmarshallAuthorizations() throws JAXBException {
try {
- final XMLStreamReader xsr = XmlUtils.createSafeReader(new StreamSource(authorizationsFile));
+ final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
+ final XMLStreamReader xsr = provider.getStreamReader(new StreamSource(authorizationsFile));
final Unmarshaller unmarshaller = JAXB_AUTHORIZATIONS_CONTEXT.createUnmarshaller();
unmarshaller.setSchema(authorizationsSchema);
final JAXBElement<Authorizations> element = unmarshaller.unmarshal(xsr, Authorizations.class);
return element.getValue();
- } catch (XMLStreamException e) {
+ } catch (final ProcessingException e) {
logger.error("Encountered an error reading authorizations file: ", e);
throw new JAXBException("Error reading authorizations file", e);
}
@@ -757,8 +759,9 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
final XMLStreamReader xsr;
try {
- xsr = XmlUtils.createSafeReader(new StreamSource(authorizedUsersFile));
- } catch (XMLStreamException e) {
+ final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
+ xsr = provider.getStreamReader(new StreamSource(authorizedUsersFile));
+ } catch (final ProcessingException e) {
logger.error("Encountered an error reading authorized users file: ", e);
throw new JAXBException("Error reading authorized users file", e);
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileUserGroupProvider.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileUserGroupProvider.java
index f59f718dbe..855e80a331 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileUserGroupProvider.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileUserGroupProvider.java
@@ -28,16 +28,18 @@ import org.apache.nifi.authorization.file.tenants.generated.Users;
import org.apache.nifi.authorization.util.IdentityMapping;
import org.apache.nifi.authorization.util.IdentityMappingUtil;
import org.apache.nifi.components.PropertyValue;
-import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.util.NiFiProperties;
import org.apache.nifi.util.file.FileUtils;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
+import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLStreamReaderProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
@@ -45,8 +47,6 @@ import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
@@ -598,8 +598,8 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
final byte[] fingerprintBytes = fingerprint.getBytes(StandardCharsets.UTF_8);
try (final ByteArrayInputStream in = new ByteArrayInputStream(fingerprintBytes)) {
- final DocumentBuilder docBuilder = XmlUtils.createSafeDocumentBuilder(false);
- final Document document = docBuilder.parse(in);
+ final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
+ final Document document = documentProvider.parse(in);
final Element rootElement = document.getDocumentElement();
// parse all the users and add them to the current user group provider
@@ -615,7 +615,7 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
Node groupNode = groupNodes.item(i);
groups.add(parseGroup((Element) groupNode));
}
- } catch (SAXException | ParserConfigurationException | IOException e) {
+ } catch (final ProcessingException | IOException e) {
throw new AuthorizationAccessException("Unable to parse fingerprint", e);
}
@@ -724,11 +724,12 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
final Unmarshaller unmarshaller = JAXB_TENANTS_CONTEXT.createUnmarshaller();
unmarshaller.setSchema(tenantsSchema);
+ final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
try {
- final XMLStreamReader xsr = XmlUtils.createSafeReader(new StreamSource(tenantsFile));
+ final XMLStreamReader xsr = provider.getStreamReader(new StreamSource(tenantsFile));
final JAXBElement<Tenants> element = unmarshaller.unmarshal(xsr, Tenants.class);
return element.getValue();
- } catch (XMLStreamException e) {
+ } catch (final ProcessingException e) {
throw new JAXBException("Error unmarshalling tenants", e);
}
}
@@ -752,10 +753,11 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
throw new AuthorizerCreationException("Legacy Authorized Users File '" + legacyAuthorizedUsersFile + "' does not exists");
}
- XMLStreamReader xsr;
+ final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
+ final XMLStreamReader xsr;
try {
- xsr = XmlUtils.createSafeReader(new StreamSource(authorizedUsersFile));
- } catch (XMLStreamException e) {
+ xsr = provider.getStreamReader(new StreamSource(authorizedUsersFile));
+ } catch (final ProcessingException e) {
throw new AuthorizerCreationException("Error converting the legacy authorizers file", e);
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/groovy/org/apache/nifi/authorization/FlowParserTest.groovy b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/groovy/org/apache/nifi/authorization/FlowParserTest.groovy
deleted file mode 100644
index fbf4b16b58..0000000000
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/groovy/org/apache/nifi/authorization/FlowParserTest.groovy
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.nifi.authorization
-
-import org.apache.nifi.util.FlowParser
-import org.junit.After
-import org.junit.Before
-import org.junit.BeforeClass
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-import org.slf4j.Logger
-import org.slf4j.LoggerFactory
-
-@RunWith(JUnit4.class)
-class FlowParserTest extends GroovyTestCase {
- private static final Logger logger = LoggerFactory.getLogger(FlowParserTest.class)
-
- @BeforeClass
- static void setUpOnce() throws Exception {
- logger.metaClass.methodMissing = { String name, args ->
- logger.info("[${name?.toUpperCase()}] ${(args as List).join(" ")}")
- }
- }
-
- @Before
- void setUp() throws Exception {
-
- }
-
- @After
- void tearDown() throws Exception {
-
- }
-
- @Test
- void testShouldHandleXXEInDocumentBuilder() {
- // Arrange
- final String XXE_TEMPLATE_FILEPATH = "src/test/resources/flow-with-xxe.xml.gz"
-
- FlowParser fp = new FlowParser()
-
- // Act
- def parsedFlow = fp.parse(new File(XXE_TEMPLATE_FILEPATH))
- logger.info("Parsed ${parsedFlow.toString()}")
-
- // Assert
-
- // The existing logic logs & swallows any exceptions and returns null
- assert !parsedFlow
- }
-}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow-with-xxe.xml.gz b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow-with-xxe.xml.gz
deleted file mode 100644
index 241f004753..0000000000
Binary files a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/test/resources/flow-with-xxe.xml.gz and /dev/null differ
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization-providers/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization-providers/pom.xml
index cdfda0a611..0dfac63311 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization-providers/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization-providers/pom.xml
@@ -42,6 +42,11 @@
<artifactId>nifi-security-utils</artifactId>
<version>1.16.1-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization-providers/src/main/java/org/apache/nifi/authorization/StandardManagedAuthorizer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization-providers/src/main/java/org/apache/nifi/authorization/StandardManagedAuthorizer.java
index b6d09298e4..d115794fd7 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization-providers/src/main/java/org/apache/nifi/authorization/StandardManagedAuthorizer.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-authorization-providers/src/main/java/org/apache/nifi/authorization/StandardManagedAuthorizer.java
@@ -22,15 +22,13 @@ import org.apache.nifi.authorization.exception.AuthorizerCreationException;
import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
import org.apache.nifi.authorization.exception.UninheritableAuthorizationsException;
import org.apache.nifi.components.PropertyValue;
-import org.apache.nifi.security.xml.XmlUtils;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
@@ -239,12 +237,13 @@ public class StandardManagedAuthorizer implements ManagedAuthorizer {
}
}
- private final FingerprintHolder parseFingerprint(final String fingerprint) throws AuthorizationAccessException {
+ private FingerprintHolder parseFingerprint(final String fingerprint) throws AuthorizationAccessException {
final byte[] fingerprintBytes = fingerprint.getBytes(StandardCharsets.UTF_8);
try (final ByteArrayInputStream in = new ByteArrayInputStream(fingerprintBytes)) {
- final DocumentBuilder docBuilder = XmlUtils.createSafeDocumentBuilder(true);
- final Document document = docBuilder.parse(in);
+ final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
+ documentProvider.setNamespaceAware(true);
+ final Document document = documentProvider.parse(in);
final Element rootElement = document.getDocumentElement();
final NodeList accessPolicyProviderList = rootElement.getElementsByTagName(ACCESS_POLICY_PROVIDER_ELEMENT);
@@ -260,7 +259,7 @@ public class StandardManagedAuthorizer implements ManagedAuthorizer {
final Node accessPolicyProvider = accessPolicyProviderList.item(0);
final Node userGroupProvider = userGroupProviderList.item(0);
return new FingerprintHolder(accessPolicyProvider.getTextContent(), userGroupProvider.getTextContent());
- } catch (SAXException | ParserConfigurationException | IOException e) {
+ } catch (final ProcessingException | IOException e) {
throw new AuthorizationAccessException("Unable to parse fingerprint", e);
}
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster-protocol/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster-protocol/pom.xml
index 1194faaf90..215b15f8c8 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster-protocol/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster-protocol/pom.xml
@@ -47,6 +47,16 @@
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-framework-core-api</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-security-utils</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ </dependency>
<!-- spring dependencies -->
<dependency>
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster-protocol/src/main/java/org/apache/nifi/cluster/protocol/HeartbeatPayload.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster-protocol/src/main/java/org/apache/nifi/cluster/protocol/HeartbeatPayload.java
index 16aac26ce4..7e6865ac1d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster-protocol/src/main/java/org/apache/nifi/cluster/protocol/HeartbeatPayload.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster-protocol/src/main/java/org/apache/nifi/cluster/protocol/HeartbeatPayload.java
@@ -17,15 +17,17 @@
package org.apache.nifi.cluster.protocol;
import org.apache.nifi.cluster.coordination.node.NodeConnectionStatus;
-import org.apache.nifi.security.xml.XmlUtils;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLStreamReaderProvider;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.stream.StreamSource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
@@ -122,9 +124,10 @@ public class HeartbeatPayload {
public static HeartbeatPayload unmarshal(final InputStream is) throws ProtocolException {
try {
final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
- final XMLStreamReader xsr = XmlUtils.createSafeReader(is);
+ final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
+ final XMLStreamReader xsr = provider.getStreamReader(new StreamSource(is));
return (HeartbeatPayload) unmarshaller.unmarshal(xsr);
- } catch (final JAXBException | XMLStreamException e) {
+ } catch (final JAXBException | ProcessingException e) {
throw new ProtocolException(e);
}
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster-protocol/src/main/java/org/apache/nifi/cluster/protocol/StandardDataFlow.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster-protocol/src/main/java/org/apache/nifi/cluster/protocol/StandardDataFlow.java
index 52d8dff54e..30cce26b5c 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster-protocol/src/main/java/org/apache/nifi/cluster/protocol/StandardDataFlow.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster-protocol/src/main/java/org/apache/nifi/cluster/protocol/StandardDataFlow.java
@@ -22,21 +22,17 @@ import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;
import org.apache.nifi.cluster.protocol.jaxb.message.DataFlowAdapter;
import org.apache.nifi.controller.flow.VersionedDataflow;
import org.apache.nifi.controller.serialization.FlowSerializationException;
-import org.apache.nifi.security.xml.XmlUtils;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.ParserConfigurationException;
import java.io.ByteArrayInputStream;
-import java.io.IOException;
import java.io.Serializable;
-import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
@@ -48,7 +44,6 @@ import java.util.Set;
*/
@XmlJavaTypeAdapter(DataFlowAdapter.class)
public class StandardDataFlow implements Serializable, DataFlow {
- private static final URL FLOW_XSD_RESOURCE = StandardDataFlow.class.getClassLoader().getResource("/FlowConfiguration.xsd");
private static final Logger logger = LoggerFactory.getLogger(StandardDataFlow.class);
private static final long serialVersionUID = 1L;
@@ -135,21 +130,19 @@ public class StandardDataFlow implements Serializable, DataFlow {
return null;
}
- // create document by parsing proposed flow bytes
try {
- // create validating document builder
- final DocumentBuilder docBuilder = XmlUtils.createSafeDocumentBuilder(true);
- docBuilder.setErrorHandler(new DefaultHandler() {
+ final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
+ documentProvider.setNamespaceAware(true);
+ documentProvider.setErrorHandler(new DefaultHandler() {
@Override
public void error(final SAXParseException e) {
logger.warn("Schema validation error parsing Flow Configuration at line {}, col {}: {}", e.getLineNumber(), e.getColumnNumber(), e.getMessage());
}
});
- // parse flow
- return docBuilder.parse(new ByteArrayInputStream(flow));
- } catch (final SAXException | ParserConfigurationException | IOException ex) {
- throw new FlowSerializationException(ex);
+ return documentProvider.parse(new ByteArrayInputStream(flow));
+ } catch (final ProcessingException e) {
+ throw new FlowSerializationException("Flow parsing failed", e);
}
}
@@ -163,8 +156,7 @@ public class StandardDataFlow implements Serializable, DataFlow {
objectMapper.setAnnotationIntrospector(new JaxbAnnotationIntrospector(objectMapper.getTypeFactory()));
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
- final VersionedDataflow versionedDataflow = objectMapper.readValue(flow, VersionedDataflow.class);
- return versionedDataflow;
+ return objectMapper.readValue(flow, VersionedDataflow.class);
} catch (final Exception e) {
throw new FlowSerializationException("Could not parse flow as a VersionedDataflow", e);
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster-protocol/src/main/java/org/apache/nifi/cluster/protocol/jaxb/JaxbProtocolContext.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster-protocol/src/main/java/org/apache/nifi/cluster/protocol/jaxb/JaxbProtocolContext.java
index 34da349821..2baade5f6c 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster-protocol/src/main/java/org/apache/nifi/cluster/protocol/jaxb/JaxbProtocolContext.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-cluster-protocol/src/main/java/org/apache/nifi/cluster/protocol/jaxb/JaxbProtocolContext.java
@@ -19,14 +19,16 @@ package org.apache.nifi.cluster.protocol.jaxb;
import org.apache.nifi.cluster.protocol.ProtocolContext;
import org.apache.nifi.cluster.protocol.ProtocolMessageMarshaller;
import org.apache.nifi.cluster.protocol.ProtocolMessageUnmarshaller;
-import org.apache.nifi.security.xml.XmlUtils;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLStreamReaderProvider;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
-import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.stream.StreamSource;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
@@ -137,10 +139,11 @@ public class JaxbProtocolContext<T> implements ProtocolContext {
final Unmarshaller unmarshaller = jaxbCtx.createUnmarshaller();
final byte[] msg = new byte[totalBytesRead];
buffer.get(msg);
- final XMLStreamReader xsr = XmlUtils.createSafeReader(new ByteArrayInputStream(msg));
+ final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
+ final XMLStreamReader xsr = provider.getStreamReader(new StreamSource(new ByteArrayInputStream(msg)));
return (T) unmarshaller.unmarshal(xsr);
- } catch (final JAXBException | XMLStreamException e) {
+ } catch (final JAXBException | ProcessingException e) {
throw new IOException("Failed unmarshalling protocol message due to: " + e, e);
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/pom.xml
index fe9cde8bdd..4cf510291c 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/pom.xml
@@ -71,6 +71,16 @@
<artifactId>nifi-property-encryptor</artifactId>
<version>1.16.1-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-security-utils</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.nifi.registry</groupId>
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/state/config/StateManagerConfiguration.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/state/config/StateManagerConfiguration.java
index 9795a72955..fd377c9459 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/state/config/StateManagerConfiguration.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/controller/state/config/StateManagerConfiguration.java
@@ -18,21 +18,22 @@
package org.apache.nifi.controller.state.config;
import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.ParserConfigurationException;
import org.apache.nifi.components.state.Scope;
import org.apache.nifi.controller.state.ConfigParseException;
-import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.util.DomUtils;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.parsers.DocumentProvider;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import org.xml.sax.SAXException;
public class StateManagerConfiguration {
private final Map<String, StateProviderConfiguration> providers;
@@ -62,11 +63,10 @@ public class StateManagerConfiguration {
public static StateManagerConfiguration parse(final File configFile) throws IOException, ConfigParseException {
final Document document;
- DocumentBuilder builder;
- try {
- builder = XmlUtils.createSafeDocumentBuilder(false);
- document = builder.parse(configFile);
- } catch (ParserConfigurationException | SAXException e) {
+ try (final InputStream inputStream = new FileInputStream(configFile)) {
+ final DocumentProvider documentProvider = new StandardDocumentProvider();
+ document = documentProvider.parse(inputStream);
+ } catch (final ProcessingException e) {
throw new ConfigParseException("Unable to parse file " + configFile + ", as it does not appear to be a valid XML File", e);
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/pom.xml
index 2ce7837247..1e24fb444a 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/pom.xml
@@ -78,6 +78,11 @@
<artifactId>nifi-repository-encryption</artifactId>
<version>1.16.1-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-properties</artifactId>
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/cluster/BulletinsPayload.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/cluster/BulletinsPayload.java
index e8a33a5b55..8c9bc0a3df 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/cluster/BulletinsPayload.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/cluster/BulletinsPayload.java
@@ -27,12 +27,15 @@ import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
-import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.stream.StreamSource;
+
import org.apache.nifi.cluster.protocol.ProtocolException;
import org.apache.nifi.jaxb.BulletinAdapter;
import org.apache.nifi.reporting.Bulletin;
-import org.apache.nifi.security.xml.XmlUtils;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLStreamReaderProvider;
/**
* The payload of the bulletins.
@@ -80,9 +83,10 @@ public class BulletinsPayload {
public static BulletinsPayload unmarshal(final InputStream is) throws ProtocolException {
try {
final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
- final XMLStreamReader xsr = XmlUtils.createSafeReader(is);
+ final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
+ final XMLStreamReader xsr = provider.getStreamReader(new StreamSource(is));
return (BulletinsPayload) unmarshaller.unmarshal(xsr);
- } catch (final JAXBException | XMLStreamException e) {
+ } catch (final JAXBException | ProcessingException e) {
throw new ProtocolException(e);
}
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/StandardFlowSerializer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/StandardFlowSerializer.java
index 202c48f176..549b3b4f4b 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/StandardFlowSerializer.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/StandardFlowSerializer.java
@@ -48,16 +48,15 @@ import org.apache.nifi.registry.flow.FlowRegistryClient;
import org.apache.nifi.registry.flow.VersionControlInformation;
import org.apache.nifi.remote.PublicPort;
import org.apache.nifi.remote.RemoteGroupPort;
-import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.util.CharacterFilterUtils;
import org.apache.nifi.util.StringUtils;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
@@ -93,8 +92,9 @@ public class StandardFlowSerializer implements FlowSerializer<Document> {
public Document transform(final FlowController controller, final ScheduledStateLookup scheduledStateLookup) throws FlowSerializationException {
try {
// create a new, empty document
- final DocumentBuilder docBuilder = XmlUtils.createSafeDocumentBuilder(true);
- final Document doc = docBuilder.newDocument();
+ final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
+ documentProvider.setNamespaceAware(true);
+ final Document doc = documentProvider.newDocument();
// populate document with controller state
final Element rootNode = doc.createElement("flowController");
@@ -127,7 +127,7 @@ public class StandardFlowSerializer implements FlowSerializer<Document> {
}
return doc;
- } catch (final ParserConfigurationException | DOMException | TransformerFactoryConfigurationError | IllegalArgumentException e) {
+ } catch (final ProcessingException | DOMException | TransformerFactoryConfigurationError | IllegalArgumentException e) {
throw new FlowSerializationException(e);
}
}
@@ -685,10 +685,11 @@ public class StandardFlowSerializer implements FlowSerializer<Document> {
try {
final byte[] serialized = TemplateSerializer.serialize(template.getDetails());
- final DocumentBuilder docBuilder = XmlUtils.createSafeDocumentBuilder(true);
+ final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
+ documentProvider.setNamespaceAware(true);
final Document document;
try (final InputStream in = new ByteArrayInputStream(serialized)) {
- document = docBuilder.parse(in);
+ document = documentProvider.parse(in);
}
final Node templateNode = element.getOwnerDocument().importNode(document.getDocumentElement(), true);
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/ControllerServiceLoader.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/ControllerServiceLoader.java
index b1475fd00a..30261cf13b 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/ControllerServiceLoader.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/service/ControllerServiceLoader.java
@@ -24,11 +24,12 @@ import org.apache.nifi.controller.serialization.FlowFromDOMFactory;
import org.apache.nifi.encrypt.PropertyEncryptor;
import org.apache.nifi.groups.ProcessGroup;
import org.apache.nifi.reporting.BulletinRepository;
-import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.util.BundleUtils;
import org.apache.nifi.util.DomUtils;
import org.apache.nifi.web.api.dto.BundleDTO;
import org.apache.nifi.web.api.dto.ControllerServiceDTO;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
@@ -36,8 +37,6 @@ import org.w3c.dom.Element;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.ParserConfigurationException;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -60,9 +59,9 @@ public class ControllerServiceLoader {
final PropertyEncryptor encryptor, final BulletinRepository bulletinRepo, final boolean autoResumeState, final FlowEncodingVersion encodingVersion) throws IOException {
try (final InputStream in = new BufferedInputStream(serializedStream)) {
- final DocumentBuilder builder = XmlUtils.createSafeDocumentBuilder(null);
+ final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
- builder.setErrorHandler(new org.xml.sax.ErrorHandler() {
+ documentProvider.setErrorHandler(new org.xml.sax.ErrorHandler() {
@Override
public void fatalError(final SAXParseException err) throws SAXException {
@@ -92,15 +91,15 @@ public class ControllerServiceLoader {
}
});
- final Document document = builder.parse(in);
+ final Document document = documentProvider.parse(in);
final Element controllerServices = document.getDocumentElement();
final List<Element> serviceElements = DomUtils.getChildElementsByTagName(controllerServices, "controllerService");
final Map<ControllerServiceNode, Element> controllerServiceMap = ControllerServiceLoader.loadControllerServices(serviceElements, controller, parentGroup, encryptor, encodingVersion);
enableControllerServices(controllerServiceMap, controller, encryptor, autoResumeState, encodingVersion);
return new ArrayList<>(controllerServiceMap.keySet());
- } catch (SAXException | ParserConfigurationException sxe) {
- throw new IOException(sxe);
+ } catch (final ProcessingException e) {
+ throw new IOException("Parsing Controller Services failed", e);
}
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java
index abee7c26ac..4aeb52661d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/fingerprint/FingerprintFactory.java
@@ -26,27 +26,26 @@ import org.apache.nifi.controller.serialization.FlowFromDOMFactory;
import org.apache.nifi.encrypt.PropertyEncryptor;
import org.apache.nifi.encrypt.SensitiveValueEncoder;
import org.apache.nifi.nar.ExtensionManager;
-import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.util.BundleUtils;
import org.apache.nifi.util.DomUtils;
import org.apache.nifi.util.LoggingXmlParserErrorHandler;
import org.apache.nifi.web.api.dto.BundleDTO;
import org.apache.nifi.web.api.dto.ControllerServiceDTO;
import org.apache.nifi.web.api.dto.ReportingTaskDTO;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
+import org.xml.sax.ErrorHandler;
import javax.xml.XMLConstants;
-import javax.xml.parsers.DocumentBuilder;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import java.io.ByteArrayInputStream;
-import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -83,7 +82,7 @@ public class FingerprintFactory {
private static final String ENCRYPTED_VALUE_PREFIX = "enc{";
private static final String ENCRYPTED_VALUE_SUFFIX = "}";
private final PropertyEncryptor encryptor;
- private final DocumentBuilder flowConfigDocBuilder;
+ private final Schema schema;
private final ExtensionManager extensionManager;
private final SensitiveValueEncoder sensitiveValueEncoder;
@@ -95,25 +94,11 @@ public class FingerprintFactory {
this.sensitiveValueEncoder = sensitiveValueEncoder;
final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
- final Schema schema;
try {
schema = schemaFactory.newSchema(FingerprintFactory.class.getResource(FLOW_CONFIG_XSD));
} catch (final Exception e) {
throw new RuntimeException("Failed to parse schema for file flow configuration.", e);
}
- try {
- flowConfigDocBuilder = XmlUtils.createSafeDocumentBuilder(schema, true);
- flowConfigDocBuilder.setErrorHandler(new LoggingXmlParserErrorHandler("Flow Configuration", logger));
- } catch (final Exception e) {
- throw new RuntimeException("Failed to create document builder for flow configuration.", e);
- }
- }
-
- public FingerprintFactory(final PropertyEncryptor encryptor, final DocumentBuilder docBuilder, final ExtensionManager extensionManager, final SensitiveValueEncoder sensitiveValueEncoder) {
- this.encryptor = encryptor;
- this.flowConfigDocBuilder = docBuilder;
- this.extensionManager = extensionManager;
- this.sensitiveValueEncoder = sensitiveValueEncoder;
}
/**
@@ -183,9 +168,15 @@ public class FingerprintFactory {
}
try {
- return flowConfigDocBuilder.parse(new ByteArrayInputStream(flow));
- } catch (final SAXException | IOException ex) {
- throw new FingerprintException(ex);
+ final ErrorHandler errorHandler = new LoggingXmlParserErrorHandler("Flow Configuration", logger);
+ final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
+ documentProvider.setSchema(schema);
+ documentProvider.setNamespaceAware(true);
+ documentProvider.setErrorHandler(errorHandler);
+
+ return documentProvider.parse(new ByteArrayInputStream(flow));
+ } catch (final ProcessingException e) {
+ throw new FingerprintException("Flow Parsing failed", e);
}
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/StandardSnippetDeserializer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/StandardSnippetDeserializer.java
index 9aba5104f1..50b204232d 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/StandardSnippetDeserializer.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/StandardSnippetDeserializer.java
@@ -21,11 +21,14 @@ import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
-import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.stream.StreamSource;
+
import org.apache.nifi.controller.StandardSnippet;
import org.apache.nifi.controller.serialization.FlowSerializationException;
-import org.apache.nifi.security.xml.XmlUtils;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLStreamReaderProvider;
public class StandardSnippetDeserializer {
@@ -33,10 +36,11 @@ public class StandardSnippetDeserializer {
try {
JAXBContext context = JAXBContext.newInstance(StandardSnippet.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
- XMLStreamReader xsr = XmlUtils.createSafeReader(inStream);
+ final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
+ XMLStreamReader xsr = provider.getStreamReader(new StreamSource(inStream));
JAXBElement<StandardSnippet> snippetElement = unmarshaller.unmarshal(xsr, StandardSnippet.class);
return snippetElement.getValue();
- } catch (final JAXBException | XMLStreamException e) {
+ } catch (final JAXBException | ProcessingException e) {
throw new FlowSerializationException(e);
}
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/TemplateDeserializer.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/TemplateDeserializer.java
index 43e89ccf91..c62a987fa8 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/TemplateDeserializer.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/persistence/TemplateDeserializer.java
@@ -17,14 +17,15 @@
package org.apache.nifi.persistence;
import org.apache.nifi.controller.serialization.FlowSerializationException;
-import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.web.api.dto.TemplateDTO;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLStreamReaderProvider;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
-import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.stream.StreamSource;
import java.io.InputStream;
@@ -46,14 +47,16 @@ public class TemplateDeserializer {
}
public static TemplateDTO deserialize(final StreamSource source) {
+ final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
+
try {
- final XMLStreamReader xsr = XmlUtils.createSafeReader(source);
+ final XMLStreamReader xsr = provider.getStreamReader(source);
final Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
final JAXBElement<TemplateDTO> templateElement = unmarshaller.unmarshal(xsr, TemplateDTO.class);
final TemplateDTO templateDto = templateElement.getValue();
return templateDto;
- } catch (final JAXBException | XMLStreamException e) {
+ } catch (final JAXBException | ProcessingException e) {
throw new FlowSerializationException(e);
}
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/util/FlowParser.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/util/FlowParser.java
index d46e2ffacf..cc1d652eac 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/util/FlowParser.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/util/FlowParser.java
@@ -22,20 +22,21 @@ import org.apache.nifi.controller.flow.VersionedDataflow;
import org.apache.nifi.controller.serialization.FlowFromDOMFactory;
import org.apache.nifi.flow.VersionedPort;
import org.apache.nifi.flow.VersionedProcessGroup;
-import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.util.file.FileUtils;
import org.apache.nifi.web.api.dto.PortDTO;
import org.apache.nifi.web.api.dto.PositionDTO;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
+import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import javax.xml.XMLConstants;
-import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
@@ -117,7 +118,7 @@ public class FlowParser {
return parseJson(flowBytes);
} catch (final SAXException | ParserConfigurationException | IOException ex) {
- logger.error("Unable to parse flow {} due to {}", new Object[] { flowPath.toAbsolutePath(), ex });
+ logger.error("Unable to parse flow {}", flowPath.toAbsolutePath(), ex);
return null;
}
}
@@ -133,11 +134,14 @@ public class FlowParser {
private FlowInfo parseXml(final byte[] flowBytes) throws ParserConfigurationException, IOException, SAXException {
// create validating document builder
- final DocumentBuilder docBuilder = XmlUtils.createSafeDocumentBuilder(flowSchema);
- docBuilder.setErrorHandler(new LoggingXmlParserErrorHandler("Flow Configuration", logger));
+ final ErrorHandler errorHandler = new LoggingXmlParserErrorHandler("Flow Configuration", logger);
+ final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
+ documentProvider.setSchema(flowSchema);
+ documentProvider.setNamespaceAware(true);
+ documentProvider.setErrorHandler(errorHandler);
// parse the flow
- final Document document = docBuilder.parse(new ByteArrayInputStream(flowBytes));
+ final Document document = documentProvider.parse(new ByteArrayInputStream(flowBytes));
// extract the root group id
final Element rootElement = document.getDocumentElement();
@@ -236,11 +240,13 @@ public class FlowParser {
}
// create validating document builder
- final DocumentBuilder docBuilder = XmlUtils.createSafeDocumentBuilder(flowSchema);
- docBuilder.setErrorHandler(new LoggingXmlParserErrorHandler("Flow Configuration", logger));
- return docBuilder.parse(new ByteArrayInputStream(flowBytes));
- } catch (final SAXException | ParserConfigurationException | IOException ex) {
- logger.error("Unable to parse flow {} due to {}", new Object[]{flowPath.toAbsolutePath(), ex});
+ final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
+ documentProvider.setErrorHandler(new LoggingXmlParserErrorHandler("Flow Configuration", logger));
+ documentProvider.setSchema(flowSchema);
+ documentProvider.setNamespaceAware(true);
+ return documentProvider.parse(new ByteArrayInputStream(flowBytes));
+ } catch (final ProcessingException | IOException e) {
+ logger.error("Unable to parse flow {}", flowPath.toAbsolutePath(), e);
return null;
}
}
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/fingerprint/FingerprintFactoryTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/fingerprint/FingerprintFactoryTest.java
index f8961d86b9..96ee449ff7 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/fingerprint/FingerprintFactoryTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/fingerprint/FingerprintFactoryTest.java
@@ -33,21 +33,14 @@ import org.apache.nifi.nar.ExtensionManager;
import org.apache.nifi.nar.StandardExtensionDiscoveringManager;
import org.apache.nifi.remote.RemoteGroupPort;
import org.apache.nifi.remote.protocol.SiteToSiteTransportProtocol;
-import org.apache.nifi.security.xml.XmlUtils;
+import org.apache.nifi.xml.processing.parsers.DocumentProvider;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.junit.Before;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import org.xml.sax.ErrorHandler;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
-
-import javax.xml.XMLConstants;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.validation.Schema;
-import javax.xml.validation.SchemaFactory;
-import java.io.File;
+
+import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
@@ -55,7 +48,6 @@ import java.util.Collections;
import java.util.Optional;
import static org.apache.nifi.controller.serialization.ScheduledStateLookup.IDENTITY_LOOKUP;
-import static org.apache.nifi.fingerprint.FingerprintFactory.FLOW_CONFIG_XSD;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
@@ -170,12 +162,11 @@ public class FingerprintFactoryTest {
}
@Test
- public void testPublicPortWithDifferentFingerprintInAccessPolicies() throws IOException, ParserConfigurationException, SAXException {
+ public void testPublicPortWithDifferentFingerprintInAccessPolicies() throws IOException {
final String f1 = fingerprintFactory.createFingerprint(getResourceBytes("/nifi/fingerprint/flow1a.xml"), null);
assertEquals(2, StringUtils.countMatches(f1, "user1group1"));
- final DocumentBuilder docBuilder = XmlUtils.createSafeDocumentBuilder(false);
- final Document document = docBuilder.parse(new File("src/test/resources/nifi/fingerprint/public-port-with-no-policies.xml"));
+ final Document document = getDocument("src/test/resources/nifi/fingerprint/public-port-with-no-policies.xml");
final Element rootProcessGroup = document.getDocumentElement();
final StringBuilder sb = new StringBuilder();
@@ -190,9 +181,8 @@ public class FingerprintFactoryTest {
}
@Test
- public void testPublicPortWithNoAccessPoliciesFingerprint() throws ParserConfigurationException, IOException, SAXException {
- final DocumentBuilder docBuilder = XmlUtils.createSafeDocumentBuilder(false);
- final Document document = docBuilder.parse(new File("src/test/resources/nifi/fingerprint/public-port-with-no-policies.xml"));
+ public void testPublicPortWithNoAccessPoliciesFingerprint() throws IOException {
+ final Document document = getDocument("src/test/resources/nifi/fingerprint/public-port-with-no-policies.xml");
final Element rootProcessGroup = document.getDocumentElement();
final StringBuilder sb = new StringBuilder();
@@ -203,52 +193,21 @@ public class FingerprintFactoryTest {
assertTrue(fingerprint.contains("NO_GROUP_ACCESS_CONTROL"));
}
- @Test
- public void testSchemaValidation() throws IOException {
- FingerprintFactory fp = new FingerprintFactory(null, getValidatingDocumentBuilder(), extensionManager, null);
- fp.createFingerprint(getResourceBytes("/nifi/fingerprint/validating-flow.xml"), null);
+ private Document getDocument(final String filePath) throws IOException {
+ try (final FileInputStream inputStream = new FileInputStream(filePath)) {
+ final DocumentProvider documentProvider = new StandardDocumentProvider();
+ return documentProvider.parse(inputStream);
+ }
}
private byte[] getResourceBytes(final String resource) throws IOException {
return IOUtils.toByteArray(FingerprintFactoryTest.class.getResourceAsStream(resource));
}
- private DocumentBuilder getValidatingDocumentBuilder() {
- final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
- final Schema schema;
- try {
- schema = schemaFactory.newSchema(FingerprintFactory.class.getResource(FLOW_CONFIG_XSD));
- } catch (final Exception e) {
- throw new RuntimeException("Failed to parse schema for file flow configuration.", e);
- }
- try {
- DocumentBuilder docBuilder = XmlUtils.createSafeDocumentBuilder(schema, true);
- docBuilder.setErrorHandler(new ErrorHandler() {
- @Override
- public void warning(SAXParseException e) throws SAXException {
- throw e;
- }
-
- @Override
- public void error(SAXParseException e) throws SAXException {
- throw e;
- }
-
- @Override
- public void fatalError(SAXParseException e) throws SAXException {
- throw e;
- }
- });
- return docBuilder;
- } catch (final Exception e) {
- throw new RuntimeException("Failed to create document builder for flow configuration.", e);
- }
- }
-
private <T> Element serializeElement(final PropertyEncryptor encryptor, final Class<T> componentClass, final T component,
final String serializerMethodName, ScheduledStateLookup scheduledStateLookup) throws Exception {
- final DocumentBuilder docBuilder = XmlUtils.createSafeDocumentBuilder(false);
- final Document doc = docBuilder.newDocument();
+ final DocumentProvider documentProvider = new StandardDocumentProvider();
+ final Document doc = documentProvider.newDocument();
final FlowSerializer flowSerializer = new StandardFlowSerializer(encryptor);
final Method serializeMethod = StandardFlowSerializer.class.getDeclaredMethod(serializerMethodName,
@@ -394,9 +353,8 @@ public class FingerprintFactoryTest {
}
@Test
- public void testControllerServicesIncludedInGroupFingerprint() throws ParserConfigurationException, IOException, SAXException {
- final DocumentBuilder docBuilder = XmlUtils.createSafeDocumentBuilder(false);
- final Document document = docBuilder.parse(new File("src/test/resources/nifi/fingerprint/group-with-controller-services.xml"));
+ public void testControllerServicesIncludedInGroupFingerprint() throws IOException {
+ final Document document = getDocument("src/test/resources/nifi/fingerprint/group-with-controller-services.xml");
final Element processGroup = document.getDocumentElement();
final StringBuilder sb = new StringBuilder();
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/persistence/TemplateSerializerTest.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/persistence/TemplateSerializerTest.java
index c04b4ddf95..a3dbec19a1 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/persistence/TemplateSerializerTest.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/persistence/TemplateSerializerTest.java
@@ -16,11 +16,12 @@
*/
package org.apache.nifi.persistence;
-import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.util.ComponentIdGenerator;
import org.apache.nifi.web.api.dto.FlowSnippetDTO;
import org.apache.nifi.web.api.dto.ProcessorDTO;
import org.apache.nifi.web.api.dto.TemplateDTO;
+import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLStreamReaderProvider;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.diff.EditList;
import org.eclipse.jgit.diff.HistogramDiff;
@@ -32,6 +33,7 @@ import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.stream.StreamSource;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -69,7 +71,8 @@ public class TemplateSerializerTest {
ByteArrayInputStream in = new ByteArrayInputStream(serTemplate);
JAXBContext context = JAXBContext.newInstance(TemplateDTO.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
- XMLStreamReader xsr = XmlUtils.createSafeReader(in);
+ final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
+ XMLStreamReader xsr = provider.getStreamReader(new StreamSource(in));
JAXBElement<TemplateDTO> templateElement = unmarshaller.unmarshal(xsr, TemplateDTO.class);
TemplateDTO deserTemplate = templateElement.getValue();
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/pom.xml
index c4d91bd80d..a7e4698222 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/pom.xml
@@ -195,6 +195,10 @@
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-nar-utils</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ </dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-web-security</artifactId>
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ProcessorAuditor.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ProcessorAuditor.java
index 50b132f0cd..f9955eaa96 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ProcessorAuditor.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/audit/ProcessorAuditor.java
@@ -34,6 +34,8 @@ import org.apache.nifi.processor.Relationship;
import org.apache.nifi.web.api.dto.ProcessorConfigDTO;
import org.apache.nifi.web.api.dto.ProcessorDTO;
import org.apache.nifi.web.dao.ProcessorDAO;
+import org.apache.nifi.xml.processing.parsers.DocumentProvider;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
@@ -43,11 +45,9 @@ import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
-import org.xml.sax.InputSource;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import java.io.StringReader;
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collection;
@@ -180,16 +180,12 @@ public class ProcessorAuditor extends NiFiAuditor {
try {
- InputSource is = new InputSource();
- is.setCharacterStream(new StringReader(newValue));
- DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
- DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
- Document doc = dBuilder.parse(is);
+ final DocumentProvider documentProvider = new StandardDocumentProvider();
+ Document doc = documentProvider.parse(new ByteArrayInputStream(newValue.getBytes(StandardCharsets.UTF_8)));
NodeList nList = doc.getChildNodes();
final Map<String, Node> xmlDumpNew = new HashMap<>();
getItemPaths(nList, ""+doc.getNodeName(), xmlDumpNew);
- is.setCharacterStream(new StringReader(oldValue));
- doc = dBuilder.parse(is);
+ doc = documentProvider.parse(new ByteArrayInputStream(oldValue.getBytes(StandardCharsets.UTF_8)));
nList = doc.getChildNodes();
final Map<String, Node> xmlDumpOld = new HashMap<>();
getItemPaths(nList, ""+doc.getNodeName(), xmlDumpOld);
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java
index c04204b9d8..1c946c72ba 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java
@@ -78,6 +78,8 @@ import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.stream.StreamSource;
+
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.nifi.authorization.AuthorizableLookup;
@@ -113,7 +115,6 @@ import org.apache.nifi.flow.VersionedProcessGroup;
import org.apache.nifi.registry.variable.VariableRegistryUpdateRequest;
import org.apache.nifi.registry.variable.VariableRegistryUpdateStep;
import org.apache.nifi.remote.util.SiteToSiteRestApiClient;
-import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.web.ResourceNotFoundException;
import org.apache.nifi.web.Revision;
import org.apache.nifi.web.api.dto.AffectedComponentDTO;
@@ -173,6 +174,8 @@ import org.apache.nifi.web.api.request.ClientIdParameter;
import org.apache.nifi.web.api.request.LongParameter;
import org.apache.nifi.web.security.token.NiFiAuthenticationToken;
import org.apache.nifi.web.util.Pause;
+import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLStreamReaderProvider;
import org.glassfish.jersey.media.multipart.FormDataParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -3814,7 +3817,8 @@ public class ProcessGroupResource extends FlowUpdateResource<ProcessGroupImportE
// TODO: Potentially refactor the template parsing to a service layer outside of the resource for web request handling
JAXBContext context = JAXBContext.newInstance(TemplateDTO.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
- XMLStreamReader xsr = XmlUtils.createSafeReader(in);
+ final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
+ XMLStreamReader xsr = provider.getStreamReader(new StreamSource(in));
JAXBElement<TemplateDTO> templateElement = unmarshaller.unmarshal(xsr, TemplateDTO.class);
template = templateElement.getValue();
} catch (JAXBException jaxbe) {
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java
index 75120aeede..f8c9967d9e 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java
+++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-security/src/main/java/org/apache/nifi/web/security/spring/LoginIdentityProviderFactoryBean.java
@@ -33,8 +33,9 @@ import org.apache.nifi.bundle.Bundle;
import org.apache.nifi.nar.ExtensionManager;
import org.apache.nifi.nar.NarCloseable;
import org.apache.nifi.properties.SensitivePropertyProviderFactoryAware;
-import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLStreamReaderProvider;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.xml.sax.SAXException;
@@ -138,7 +139,8 @@ public class LoginIdentityProviderFactoryBean extends SensitivePropertyProviderF
final Schema schema = schemaFactory.newSchema(LoginIdentityProviders.class.getResource(LOGIN_IDENTITY_PROVIDERS_XSD));
// attempt to unmarshal
- XMLStreamReader xsr = XmlUtils.createSafeReader(new StreamSource(loginIdentityProvidersConfigurationFile));
+ final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
+ XMLStreamReader xsr = provider.getStreamReader(new StreamSource(loginIdentityProvidersConfigurationFile));
final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
unmarshaller.setSchema(schema);
final JAXBElement<LoginIdentityProviders> element = unmarshaller.unmarshal(xsr, LoginIdentityProviders.class);
diff --git a/nifi-nar-bundles/nifi-framework-bundle/pom.xml b/nifi-nar-bundles/nifi-framework-bundle/pom.xml
index 39a976b8b3..e9e1d304cc 100644
--- a/nifi-nar-bundles/nifi-framework-bundle/pom.xml
+++ b/nifi-nar-bundles/nifi-framework-bundle/pom.xml
@@ -59,6 +59,11 @@
<artifactId>nifi-security-utils-api</artifactId>
<version>1.16.1-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-expression-language</artifactId>
diff --git a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/pom.xml b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/pom.xml
index 3048a4e3cd..22be8d9cc6 100644
--- a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/pom.xml
+++ b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/pom.xml
@@ -186,7 +186,7 @@
</dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
- <artifactId>nifi-security-utils</artifactId>
+ <artifactId>nifi-xml-processing</artifactId>
<version>1.16.1-SNAPSHOT</version>
</dependency>
<dependency>
diff --git a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/ManagedRangerAuthorizer.java b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/ManagedRangerAuthorizer.java
index f427346d55..4f5f340ff6 100644
--- a/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/ManagedRangerAuthorizer.java
+++ b/nifi-nar-bundles/nifi-ranger-bundle/nifi-ranger-plugin/src/main/java/org/apache/nifi/ranger/authorization/ManagedRangerAuthorizer.java
@@ -23,8 +23,6 @@ import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.StandardCharsets;
import java.util.Set;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
@@ -45,12 +43,12 @@ import org.apache.nifi.authorization.exception.AuthorizationAccessException;
import org.apache.nifi.authorization.exception.AuthorizerCreationException;
import org.apache.nifi.authorization.exception.AuthorizerDestructionException;
import org.apache.nifi.authorization.exception.UninheritableAuthorizationsException;
-import org.apache.nifi.security.xml.XmlUtils;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
public class ManagedRangerAuthorizer extends RangerNiFiAuthorizer implements ManagedAuthorizer {
private static final String USER_GROUP_PROVIDER_ELEMENT = "userGroupProvider";
@@ -128,8 +126,8 @@ public class ManagedRangerAuthorizer extends RangerNiFiAuthorizer implements Man
final StringWriter out = new StringWriter();
try {
// create the document
- final DocumentBuilder documentBuilder = XmlUtils.createSafeDocumentBuilder(false);
- final Document document = documentBuilder.newDocument();
+ final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
+ final Document document = documentProvider.newDocument();
// create the root element
final Element managedRangerAuthorizationsElement = document.createElement("managedRangerAuthorizations");
@@ -146,7 +144,7 @@ public class ManagedRangerAuthorizer extends RangerNiFiAuthorizer implements Man
final Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(new DOMSource(document), new StreamResult(out));
- } catch (ParserConfigurationException | TransformerException e) {
+ } catch (final ProcessingException | TransformerException e) {
throw new AuthorizationAccessException("Unable to generate fingerprint", e);
}
@@ -192,8 +190,8 @@ public class ManagedRangerAuthorizer extends RangerNiFiAuthorizer implements Man
final byte[] fingerprintBytes = fingerprint.getBytes(StandardCharsets.UTF_8);
try (final ByteArrayInputStream in = new ByteArrayInputStream(fingerprintBytes)) {
- final DocumentBuilder docBuilder = XmlUtils.createSafeDocumentBuilder(false);
- final Document document = docBuilder.parse(in);
+ final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
+ final Document document = documentProvider.parse(in);
final Element rootElement = document.getDocumentElement();
final NodeList userGroupProviderList = rootElement.getElementsByTagName(USER_GROUP_PROVIDER_ELEMENT);
@@ -203,7 +201,7 @@ public class ManagedRangerAuthorizer extends RangerNiFiAuthorizer implements Man
final Node userGroupProvider = userGroupProviderList.item(0);
return userGroupProvider.getTextContent();
- } catch (SAXException | ParserConfigurationException | IOException e) {
+ } catch (final ProcessingException | IOException e) {
throw new AuthorizationAccessException("Unable to parse fingerprint", e);
}
}
diff --git a/nifi-nar-bundles/nifi-single-user-iaa-providers-bundle/nifi-single-user-iaa-providers/pom.xml b/nifi-nar-bundles/nifi-single-user-iaa-providers-bundle/nifi-single-user-iaa-providers/pom.xml
index 475190aaec..3710fb8b1b 100644
--- a/nifi-nar-bundles/nifi-single-user-iaa-providers-bundle/nifi-single-user-iaa-providers/pom.xml
+++ b/nifi-nar-bundles/nifi-single-user-iaa-providers-bundle/nifi-single-user-iaa-providers/pom.xml
@@ -46,6 +46,11 @@
<artifactId>nifi-single-user-utils</artifactId>
<version>1.16.1-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ </dependency>
</dependencies>
<scm>
diff --git a/nifi-nar-bundles/nifi-single-user-iaa-providers-bundle/nifi-single-user-iaa-providers/src/main/java/org/apache/nifi/authorization/single/user/SingleUserAuthorizer.java b/nifi-nar-bundles/nifi-single-user-iaa-providers-bundle/nifi-single-user-iaa-providers/src/main/java/org/apache/nifi/authorization/single/user/SingleUserAuthorizer.java
index 9aeb130487..e78e386555 100644
--- a/nifi-nar-bundles/nifi-single-user-iaa-providers-bundle/nifi-single-user-iaa-providers/src/main/java/org/apache/nifi/authorization/single/user/SingleUserAuthorizer.java
+++ b/nifi-nar-bundles/nifi-single-user-iaa-providers-bundle/nifi-single-user-iaa-providers/src/main/java/org/apache/nifi/authorization/single/user/SingleUserAuthorizer.java
@@ -26,14 +26,16 @@ import org.apache.nifi.authorization.annotation.AuthorizerContext;
import org.apache.nifi.authorization.exception.AuthorizationAccessException;
import org.apache.nifi.authorization.exception.AuthorizerCreationException;
import org.apache.nifi.util.NiFiProperties;
+import org.apache.nifi.xml.processing.stream.StandardXMLEventReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLEventReaderProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.xml.stream.XMLEventReader;
-import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
+import javax.xml.transform.stream.StreamSource;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@@ -149,9 +151,7 @@ public class SingleUserAuthorizer implements Authorizer {
}
private XMLEventReader getProvidersReader(final InputStream inputStream) throws XMLStreamException {
- final XMLInputFactory inputFactory = XMLInputFactory.newFactory();
- inputFactory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
- inputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
- return inputFactory.createXMLEventReader(inputStream);
+ final XMLEventReaderProvider readerProvider = new StandardXMLEventReaderProvider();
+ return readerProvider.getEventReader(new StreamSource(inputStream));
}
}
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/pom.xml b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/pom.xml
index bb34818800..637111470e 100644
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/pom.xml
+++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/pom.xml
@@ -158,6 +158,11 @@
<artifactId>nifi-security-utils</artifactId>
<version>1.16.1-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>com.hierynomus</groupId>
<artifactId>sshj</artifactId>
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EvaluateXPath.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EvaluateXPath.java
index ae5020689f..de1c05424b 100644
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EvaluateXPath.java
+++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EvaluateXPath.java
@@ -22,11 +22,9 @@ import static javax.xml.xpath.XPathConstants.STRING;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
-import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.io.StringReader;
-import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -46,12 +44,11 @@ import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
-import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
-import javax.xml.xpath.XPathFactoryConfigurationException;
import org.apache.nifi.annotation.behavior.DynamicProperty;
import org.apache.nifi.annotation.behavior.EventDriven;
@@ -59,6 +56,9 @@ import org.apache.nifi.annotation.behavior.InputRequirement;
import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
import org.apache.nifi.annotation.behavior.SideEffectFree;
import org.apache.nifi.annotation.behavior.SupportsBatching;
+import org.apache.nifi.annotation.behavior.SystemResource;
+import org.apache.nifi.annotation.behavior.SystemResourceConsideration;
+import org.apache.nifi.annotation.behavior.SystemResourceConsiderations;
import org.apache.nifi.annotation.behavior.WritesAttribute;
import org.apache.nifi.annotation.documentation.CapabilityDescription;
import org.apache.nifi.annotation.documentation.Tags;
@@ -76,16 +76,14 @@ import org.apache.nifi.processor.ProcessSession;
import org.apache.nifi.processor.ProcessorInitializationContext;
import org.apache.nifi.processor.Relationship;
import org.apache.nifi.processor.exception.ProcessException;
-import org.apache.nifi.processor.io.InputStreamCallback;
-import org.apache.nifi.processor.io.OutputStreamCallback;
-import org.xml.sax.EntityResolver;
-import org.xml.sax.InputSource;
+import org.apache.nifi.processors.standard.xml.DocumentTypeAllowedDocumentProvider;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
+import org.w3c.dom.Document;
-import net.sf.saxon.lib.NamespaceConstant;
import net.sf.saxon.xpath.XPathEvaluator;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.XMLReaderFactory;
+import net.sf.saxon.xpath.XPathFactoryImpl;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
@EventDriven
@SideEffectFree
@@ -105,6 +103,9 @@ import org.xml.sax.helpers.XMLReaderFactory;
@WritesAttribute(attribute = "user-defined", description = "This processor adds user-defined attributes if the <Destination> property is set to flowfile-attribute.")
@DynamicProperty(name = "A FlowFile attribute(if <Destination> is set to 'flowfile-attribute'", value = "An XPath expression", description = "If <Destination>='flowfile-attribute' "
+ "then the FlowFile attribute is set to the result of the XPath Expression. If <Destination>='flowfile-content' then the FlowFile content is set to the result of the XPath Expression.")
+@SystemResourceConsiderations({
+ @SystemResourceConsideration(resource = SystemResource.MEMORY, description = "Processing requires reading the entire FlowFile into memory")
+})
public class EvaluateXPath extends AbstractProcessor {
public static final String DESTINATION_ATTRIBUTE = "flowfile-attribute";
@@ -137,7 +138,7 @@ public class EvaluateXPath extends AbstractProcessor {
.description("Specifies whether or not the XML content should be validated against the DTD.")
.required(true)
.allowableValues("true", "false")
- .defaultValue("true")
+ .defaultValue("false")
.build();
public static final Relationship REL_MATCH = new Relationship.Builder()
@@ -162,10 +163,6 @@ public class EvaluateXPath extends AbstractProcessor {
private final AtomicReference<XPathFactory> factoryRef = new AtomicReference<>();
- static {
- System.setProperty("javax.xml.xpath.XPathFactory:" + NamespaceConstant.OBJECT_MODEL_SAXON, "net.sf.saxon.xpath.XPathFactoryImpl");
- }
-
@Override
protected void init(final ProcessorInitializationContext context) {
final Set<Relationship> relationships = new HashSet<>();
@@ -215,8 +212,8 @@ public class EvaluateXPath extends AbstractProcessor {
}
@OnScheduled
- public void initializeXPathFactory() throws XPathFactoryConfigurationException {
- factoryRef.set(XPathFactory.newInstance(NamespaceConstant.OBJECT_MODEL_SAXON));
+ public void initializeXPathFactory() {
+ factoryRef.set(new XPathFactoryImpl());
}
@Override
@@ -231,7 +228,6 @@ public class EvaluateXPath extends AbstractProcessor {
}
@Override
- @SuppressWarnings("unchecked")
public void onTrigger(final ProcessContext context, final ProcessSession session) {
final List<FlowFile> flowFiles = session.get(50);
if (flowFiles.isEmpty()) {
@@ -239,23 +235,6 @@ public class EvaluateXPath extends AbstractProcessor {
}
final ComponentLog logger = getLogger();
- final XMLReader xmlReader;
-
- try {
- xmlReader = XMLReaderFactory.createXMLReader();
- } catch (SAXException e) {
- logger.error("Error while constructing XMLReader {}", new Object[]{e});
- throw new ProcessException(e.getMessage());
- }
-
- if (!context.getProperty(VALIDATE_DTD).asBoolean()) {
- xmlReader.setEntityResolver(new EntityResolver() {
- @Override
- public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
- return new InputSource(new StringReader(""));
- }
- });
- }
final XPathFactory factory = factoryRef.get();
final XPathEvaluator xpathEvaluator = (XPathEvaluator) factory.newXPath();
@@ -274,15 +253,6 @@ public class EvaluateXPath extends AbstractProcessor {
}
}
- final XPathExpression slashExpression;
- try {
- slashExpression = xpathEvaluator.compile("/");
- } catch (XPathExpressionException e) {
- logger.error("unable to compile XPath expression due to {}", new Object[]{e});
- session.transfer(flowFiles, REL_FAILURE);
- return;
- }
-
final String destination = context.getProperty(DESTINATION).getValue();
final QName returnType;
@@ -306,27 +276,25 @@ public class EvaluateXPath extends AbstractProcessor {
throw new IllegalStateException("There are no other return types...");
}
+ final boolean validatingDeclaration = context.getProperty(VALIDATE_DTD).asBoolean();
+
flowFileLoop:
for (FlowFile flowFile : flowFiles) {
final AtomicReference<Throwable> error = new AtomicReference<>(null);
final AtomicReference<Source> sourceRef = new AtomicReference<>(null);
- session.read(flowFile, new InputStreamCallback() {
- @Override
- public void process(final InputStream rawIn) throws IOException {
+ try {
+ session.read(flowFile, rawIn -> {
try (final InputStream in = new BufferedInputStream(rawIn)) {
- final List<Source> rootList = (List<Source>) slashExpression.evaluate(new SAXSource(xmlReader,
- new InputSource(in)), NODESET);
- sourceRef.set(rootList.get(0));
- } catch (final Exception e) {
- error.set(e);
+ final StandardDocumentProvider documentProvider = validatingDeclaration
+ ? new DocumentTypeAllowedDocumentProvider()
+ : new StandardDocumentProvider();
+ final Document document = documentProvider.parse(in);
+ sourceRef.set(new DOMSource(document));
}
- }
- });
-
- if (error.get() != null) {
- logger.error("unable to evaluate XPath against {} due to {}; routing to 'failure'",
- new Object[]{flowFile, error.get()});
+ });
+ } catch (final Exception e) {
+ logger.error("Input parsing failed {}", flowFile, e);
session.transfer(flowFile, REL_FAILURE);
continue;
}
@@ -334,69 +302,60 @@ public class EvaluateXPath extends AbstractProcessor {
final Map<String, String> xpathResults = new HashMap<>();
for (final Map.Entry<String, XPathExpression> entry : attributeToXPathMap.entrySet()) {
- Object result = null;
+ Object result;
try {
result = entry.getValue().evaluate(sourceRef.get(), returnType);
if (result == null) {
continue;
}
} catch (final XPathExpressionException e) {
- logger.error("failed to evaluate XPath for {} for Property {} due to {}; routing to failure",
- new Object[]{flowFile, entry.getKey(), e});
+ logger.error("XPath Property [{}] evaluation on {} failed", flowFile, entry.getKey(), e);
session.transfer(flowFile, REL_FAILURE);
continue flowFileLoop;
}
if (returnType == NODESET) {
- List<Source> nodeList = (List<Source>) result;
- if (nodeList.isEmpty()) {
- logger.info("Routing {} to 'unmatched'", new Object[]{flowFile});
+ final NodeList nodeList = (NodeList) result;
+ if (nodeList.getLength() == 0) {
+ logger.info("XPath evaluation on {} produced no results", flowFile);
session.transfer(flowFile, REL_NO_MATCH);
continue flowFileLoop;
- } else if (nodeList.size() > 1) {
- logger.error("Routing {} to 'failure' because the XPath evaluated to {} XML nodes",
- new Object[]{flowFile, nodeList.size()});
+ } else if (nodeList.getLength() > 1) {
+ logger.error("XPath evaluation on {} produced unexpected results [{}]", flowFile, nodeList.getLength());
session.transfer(flowFile, REL_FAILURE);
continue flowFileLoop;
}
- final Source sourceNode = nodeList.get(0);
+ final Node firstNode = nodeList.item(0);
+ final Source sourceNode = new DOMSource(firstNode);
if (DESTINATION_ATTRIBUTE.equals(destination)) {
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
doTransform(sourceNode, baos);
- xpathResults.put(entry.getKey(), baos.toString("UTF-8"));
- } catch (UnsupportedEncodingException e) {
- throw new ProcessException(e);
+ xpathResults.put(entry.getKey(), new String(baos.toByteArray(), StandardCharsets.UTF_8));
} catch (TransformerException e) {
error.set(e);
}
} else if (DESTINATION_CONTENT.equals(destination)) {
- flowFile = session.write(flowFile, new OutputStreamCallback() {
- @Override
- public void process(final OutputStream rawOut) throws IOException {
- try (final OutputStream out = new BufferedOutputStream(rawOut)) {
- doTransform(sourceNode, out);
- } catch (TransformerException e) {
- error.set(e);
- }
+ flowFile = session.write(flowFile, rawOut -> {
+ try (final OutputStream out = new BufferedOutputStream(rawOut)) {
+ doTransform(sourceNode, out);
+ } catch (TransformerException e) {
+ error.set(e);
}
});
}
- } else if (returnType == STRING) {
+ } else {
final String resultString = (String) result;
if (DESTINATION_ATTRIBUTE.equals(destination)) {
xpathResults.put(entry.getKey(), resultString);
} else if (DESTINATION_CONTENT.equals(destination)) {
- flowFile = session.write(flowFile, new OutputStreamCallback() {
- @Override
- public void process(final OutputStream rawOut) throws IOException {
- try (final OutputStream out = new BufferedOutputStream(rawOut)) {
- out.write(resultString.getBytes("UTF-8"));
- }
+ flowFile = session.write(flowFile, rawOut -> {
+ try (final OutputStream out = new BufferedOutputStream(rawOut)) {
+ out.write(resultString.getBytes(StandardCharsets.UTF_8));
}
});
}
@@ -407,18 +366,16 @@ public class EvaluateXPath extends AbstractProcessor {
if (DESTINATION_ATTRIBUTE.equals(destination)) {
flowFile = session.putAllAttributes(flowFile, xpathResults);
final Relationship destRel = xpathResults.isEmpty() ? REL_NO_MATCH : REL_MATCH;
- logger.info("Successfully evaluated XPaths against {} and found {} matches; routing to {}",
- new Object[]{flowFile, xpathResults.size(), destRel.getName()});
+ logger.info("XPath evaluation on {} completed with results [{}]: content updated", flowFile, xpathResults.size());
session.transfer(flowFile, destRel);
session.getProvenanceReporter().modifyAttributes(flowFile);
} else if (DESTINATION_CONTENT.equals(destination)) {
- logger.info("Successfully updated content for {}; routing to 'matched'", new Object[]{flowFile});
+ logger.info("XPath evaluation on {} completed: content updated", flowFile);
session.transfer(flowFile, REL_MATCH);
session.getProvenanceReporter().modifyContent(flowFile);
}
} else {
- logger.error("Failed to write XPath result for {} due to {}; routing original to 'failure'",
- new Object[]{flowFile, error.get()});
+ logger.error("XPath evaluation on {} failed", flowFile, error.get());
session.transfer(flowFile, REL_FAILURE);
}
}
@@ -443,19 +400,19 @@ public class EvaluateXPath extends AbstractProcessor {
final AtomicReference<TransformerException> error = new AtomicReference<>(null);
transformer.setErrorListener(new ErrorListener() {
@Override
- public void warning(final TransformerException exception) throws TransformerException {
- logger.warn("Encountered warning from XPath Engine: ", new Object[]{exception.toString(), exception});
+ public void warning(final TransformerException exception) {
+ logger.warn("Encountered warning from XPath Engine", exception);
}
@Override
- public void error(final TransformerException exception) throws TransformerException {
- logger.error("Encountered error from XPath Engine: ", new Object[]{exception.toString(), exception});
+ public void error(final TransformerException exception) {
+ logger.error("Encountered error from XPath Engine", exception);
error.set(exception);
}
@Override
- public void fatalError(final TransformerException exception) throws TransformerException {
- logger.error("Encountered warning from XPath Engine: ", new Object[]{exception.toString(), exception});
+ public void fatalError(final TransformerException exception) {
+ logger.error("Encountered warning from XPath Engine", exception);
error.set(exception);
}
});
@@ -471,7 +428,7 @@ public class EvaluateXPath extends AbstractProcessor {
@Override
public ValidationResult validate(final String subject, final String input, final ValidationContext validationContext) {
try {
- XPathFactory factory = XPathFactory.newInstance(NamespaceConstant.OBJECT_MODEL_SAXON);
+ XPathFactory factory = new XPathFactoryImpl();
final XPathEvaluator evaluator = (XPathEvaluator) factory.newXPath();
String error = null;
@@ -484,7 +441,7 @@ public class EvaluateXPath extends AbstractProcessor {
return new ValidationResult.Builder().input(input).subject(subject).valid(error == null).explanation(error).build();
} catch (final Exception e) {
return new ValidationResult.Builder().input(input).subject(subject).valid(false)
- .explanation("Unable to initialize XPath engine due to " + e.toString()).build();
+ .explanation("Unable to initialize XPath engine due to " + e).build();
}
}
}
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EvaluateXQuery.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EvaluateXQuery.java
index cf58ab7aa1..7db4fdb280 100644
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EvaluateXQuery.java
+++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/EvaluateXQuery.java
@@ -22,7 +22,6 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
@@ -39,9 +38,8 @@ import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
-import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
-import net.sf.saxon.s9api.DOMDestination;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XQueryCompiler;
@@ -56,6 +54,9 @@ import org.apache.nifi.annotation.behavior.InputRequirement;
import org.apache.nifi.annotation.behavior.InputRequirement.Requirement;
import org.apache.nifi.annotation.behavior.SideEffectFree;
import org.apache.nifi.annotation.behavior.SupportsBatching;
+import org.apache.nifi.annotation.behavior.SystemResource;
+import org.apache.nifi.annotation.behavior.SystemResourceConsideration;
+import org.apache.nifi.annotation.behavior.SystemResourceConsiderations;
import org.apache.nifi.annotation.behavior.WritesAttribute;
import org.apache.nifi.annotation.documentation.CapabilityDescription;
import org.apache.nifi.annotation.documentation.Tags;
@@ -72,16 +73,10 @@ import org.apache.nifi.processor.ProcessSession;
import org.apache.nifi.processor.ProcessorInitializationContext;
import org.apache.nifi.processor.Relationship;
import org.apache.nifi.processor.exception.ProcessException;
-import org.apache.nifi.processor.io.InputStreamCallback;
-import org.apache.nifi.processor.io.OutputStreamCallback;
import org.apache.nifi.processor.util.StandardValidators;
-import org.apache.nifi.security.xml.XmlUtils;
+import org.apache.nifi.processors.standard.xml.DocumentTypeAllowedDocumentProvider;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.w3c.dom.Document;
-import org.xml.sax.EntityResolver;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.XMLReaderFactory;
@EventDriven
@SideEffectFree
@@ -103,6 +98,9 @@ import org.xml.sax.helpers.XMLReaderFactory;
@WritesAttribute(attribute = "user-defined", description = "This processor adds user-defined attributes if the <Destination> property is set to flowfile-attribute .")
@DynamicProperty(name = "A FlowFile attribute(if <Destination> is set to 'flowfile-attribute'", value = "An XQuery", description = "If <Destination>='flowfile-attribute' "
+ "then the FlowFile attribute is set to the result of the XQuery. If <Destination>='flowfile-content' then the FlowFile content is set to the result of the XQuery.")
+@SystemResourceConsiderations({
+ @SystemResourceConsideration(resource = SystemResource.MEMORY, description = "Processing requires reading the entire FlowFile into memory")
+})
public class EvaluateXQuery extends AbstractProcessor {
public static final String DESTINATION_ATTRIBUTE = "flowfile-attribute";
@@ -112,8 +110,6 @@ public class EvaluateXQuery extends AbstractProcessor {
public static final String OUTPUT_METHOD_HTML = "html";
public static final String OUTPUT_METHOD_TEXT = "text";
- public static final String UTF8 = "UTF-8";
-
public static final PropertyDescriptor DESTINATION = new PropertyDescriptor.Builder()
.name("Destination")
.description(
@@ -156,7 +152,7 @@ public class EvaluateXQuery extends AbstractProcessor {
.description("Specifies whether or not the XML content should be validated against the DTD.")
.required(true)
.allowableValues("true", "false")
- .defaultValue("true")
+ .defaultValue("false")
.build();
public static final Relationship REL_MATCH = new Relationship.Builder()
@@ -248,24 +244,6 @@ public class EvaluateXQuery extends AbstractProcessor {
final Map<String, XQueryExecutable> attributeToXQueryMap = new HashMap<>();
final Processor proc = new Processor(false);
- final XMLReader xmlReader;
-
- try {
- xmlReader = XMLReaderFactory.createXMLReader();
- } catch (SAXException e) {
- logger.error("Error while constructing XMLReader {}", new Object[]{e});
- throw new ProcessException(e.getMessage());
- }
-
- if (!context.getProperty(VALIDATE_DTD).asBoolean()) {
- xmlReader.setEntityResolver(new EntityResolver() {
- @Override
- public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
- return new InputSource(new StringReader(""));
- }
- });
- }
-
final XQueryCompiler comp = proc.newXQueryCompiler();
for (final Map.Entry<PropertyDescriptor, String> entry : context.getProperties().entrySet()) {
@@ -281,16 +259,8 @@ public class EvaluateXQuery extends AbstractProcessor {
}
}
- final XQueryExecutable slashExpression;
- try {
- slashExpression = comp.compile("/");
- } catch (SaxonApiException e) {
- logger.error("unable to compile XQuery expression due to {}", new Object[]{e});
- session.transfer(flowFileBatch, REL_FAILURE);
- return;
- }
-
final String destination = context.getProperty(DESTINATION).getValue();
+ final boolean validateDeclaration = context.getProperty(VALIDATE_DTD).asBoolean();
flowFileLoop:
for (FlowFile flowFile : flowFileBatch) {
@@ -299,28 +269,20 @@ public class EvaluateXQuery extends AbstractProcessor {
return;
}
- final AtomicReference<Throwable> error = new AtomicReference<>(null);
- final AtomicReference<XdmNode> sourceRef = new AtomicReference<>(null);
-
- session.read(flowFile, new InputStreamCallback() {
- @Override
- public void process(final InputStream rawIn) throws IOException {
+ final AtomicReference<DOMSource> sourceRef = new AtomicReference<>(null);
+ try {
+ session.read(flowFile, rawIn -> {
try (final InputStream in = new BufferedInputStream(rawIn)) {
- XQueryEvaluator qe = slashExpression.load();
- qe.setSource(new SAXSource(xmlReader, new InputSource(in)));
- Document dom = XmlUtils.createSafeDocumentBuilder(true).newDocument();
- qe.run(new DOMDestination(dom));
- XdmNode rootNode = proc.newDocumentBuilder().wrap(dom);
- sourceRef.set(rootNode);
- } catch (final Exception e) {
- error.set(e);
+ final StandardDocumentProvider documentProvider = validateDeclaration
+ ? new DocumentTypeAllowedDocumentProvider()
+ : new StandardDocumentProvider();
+ documentProvider.setNamespaceAware(true);
+ final Document document = documentProvider.parse(in);
+ sourceRef.set(new DOMSource(document));
}
- }
- });
-
- if (error.get() != null) {
- logger.error("unable to evaluate XQuery against {} due to {}; routing to 'failure'",
- new Object[]{flowFile, error.get()});
+ });
+ } catch (final Exception e) {
+ logger.error("Input parsing failed {}", flowFile, e);
session.transfer(flowFile, REL_FAILURE);
continue;
}
@@ -331,7 +293,7 @@ public class EvaluateXQuery extends AbstractProcessor {
for (final Map.Entry<String, XQueryExecutable> entry : attributeToXQueryMap.entrySet()) {
try {
XQueryEvaluator qe = entry.getValue().load();
- qe.setContextItem(sourceRef.get());
+ qe.setSource(sourceRef.get());
XdmValue result = qe.evaluate();
if (DESTINATION_ATTRIBUTE.equals(destination)) {
@@ -346,33 +308,27 @@ public class EvaluateXQuery extends AbstractProcessor {
}
} else { // if (DESTINATION_CONTENT.equals(destination)){
if (result.size() == 0) {
- logger.info("Routing {} to 'unmatched'", new Object[]{flowFile});
+ logger.info("No XQuery results found {}", flowFile);
session.transfer(flowFile, REL_NO_MATCH);
continue flowFileLoop;
} else if (result.size() == 1) {
final XdmItem item = result.itemAt(0);
- flowFile = session.write(flowFile, new OutputStreamCallback() {
- @Override
- public void process(final OutputStream rawOut) throws IOException {
- try (final OutputStream out = new BufferedOutputStream(rawOut)) {
- writeformattedItem(item, context, out);
- } catch (TransformerFactoryConfigurationError | TransformerException e) {
- throw new IOException(e);
- }
+ flowFile = session.write(flowFile, rawOut -> {
+ try (final OutputStream out = new BufferedOutputStream(rawOut)) {
+ writeformattedItem(item, context, out);
+ } catch (TransformerFactoryConfigurationError | TransformerException e) {
+ throw new IOException(e);
}
});
} else {
for (final XdmItem item : result) {
FlowFile ff = session.clone(flowFile);
- ff = session.write(ff, new OutputStreamCallback() {
- @Override
- public void process(final OutputStream rawOut) throws IOException {
- try (final OutputStream out = new BufferedOutputStream(rawOut)) {
- try {
- writeformattedItem(item, context, out);
- } catch (TransformerFactoryConfigurationError | TransformerException e) {
- throw new IOException(e);
- }
+ ff = session.write(ff, rawOut -> {
+ try (final OutputStream out = new BufferedOutputStream(rawOut)) {
+ try {
+ writeformattedItem(item, context, out);
+ } catch (TransformerFactoryConfigurationError | TransformerException e) {
+ throw new IOException(e);
}
}
});
@@ -381,14 +337,12 @@ public class EvaluateXQuery extends AbstractProcessor {
}
}
} catch (final SaxonApiException e) {
- logger.error("failed to evaluate XQuery for {} for Property {} due to {}; routing to failure",
- new Object[]{flowFile, entry.getKey(), e});
+ logger.error("XQuery Property [{}] processing failed", entry.getKey(), e);
session.transfer(flowFile, REL_FAILURE);
session.remove(childrenFlowFiles);
continue flowFileLoop;
} catch (TransformerFactoryConfigurationError | TransformerException | IOException e) {
- logger.error("Failed to write XQuery result for {} due to {}; routing original to 'failure'",
- new Object[]{flowFile, error.get()});
+ logger.error("XQuery Property [{}] configuration failed", entry.getKey(), e);
session.transfer(flowFile, REL_FAILURE);
session.remove(childrenFlowFiles);
continue flowFileLoop;
@@ -398,18 +352,16 @@ public class EvaluateXQuery extends AbstractProcessor {
if (DESTINATION_ATTRIBUTE.equals(destination)) {
flowFile = session.putAllAttributes(flowFile, xQueryResults);
final Relationship destRel = xQueryResults.isEmpty() ? REL_NO_MATCH : REL_MATCH;
- logger.info("Successfully evaluated XQueries against {} and found {} matches; routing to {}",
- new Object[]{flowFile, xQueryResults.size(), destRel.getName()});
+ logger.info("XQuery results found [{}] for {}", xQueryResults.size(), flowFile);
session.transfer(flowFile, destRel);
session.getProvenanceReporter().modifyAttributes(flowFile);
} else { // if (DESTINATION_CONTENT.equals(destination)) {
if (!childrenFlowFiles.isEmpty()) {
- logger.info("Successfully created {} new FlowFiles from {}; routing all to 'matched'",
- new Object[]{childrenFlowFiles.size(), flowFile});
+ logger.info("XQuery results found [{}] for {} FlowFiles created [{}]", xQueryResults.size(), flowFile, childrenFlowFiles.size());
session.transfer(childrenFlowFiles, REL_MATCH);
session.remove(flowFile);
} else {
- logger.info("Successfully updated content for {}; routing to 'matched'", new Object[]{flowFile});
+ logger.info("XQuery results found for {} content updated", flowFile);
session.transfer(flowFile, REL_MATCH);
session.getProvenanceReporter().modifyContent(flowFile);
}
@@ -475,7 +427,7 @@ public class EvaluateXQuery extends AbstractProcessor {
return new ValidationResult.Builder().input(input).subject(subject).valid(error == null).explanation(error).build();
} catch (final Exception e) {
return new ValidationResult.Builder().input(input).subject(subject).valid(false)
- .explanation("Unable to initialize XQuery engine due to " + e.toString()).build();
+ .explanation("Unable to initialize XQuery engine due to " + e).build();
}
}
}
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/SplitXml.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/SplitXml.java
index 889c5672a3..812b5c0a3a 100644
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/SplitXml.java
+++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/SplitXml.java
@@ -23,6 +23,7 @@ import static org.apache.nifi.flowfile.attributes.FragmentAttributes.SEGMENT_ORI
import static org.apache.nifi.flowfile.attributes.FragmentAttributes.copyAttributesToOriginal;
import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
@@ -34,8 +35,6 @@ import java.util.TreeMap;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
-import javax.xml.parsers.ParserConfigurationException;
-import javax.xml.parsers.SAXParserFactory;
import org.apache.commons.text.StringEscapeUtils;
import org.apache.nifi.annotation.behavior.EventDriven;
import org.apache.nifi.annotation.behavior.SystemResourceConsideration;
@@ -59,15 +58,13 @@ import org.apache.nifi.processor.ProcessorInitializationContext;
import org.apache.nifi.processor.Relationship;
import org.apache.nifi.processor.util.StandardValidators;
import org.apache.nifi.processors.standard.util.XmlElementNotifier;
-import org.apache.nifi.security.xml.XmlUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.sax.StandardInputSourceParser;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
@EventDriven
@SideEffectFree
@@ -115,22 +112,6 @@ public class SplitXml extends AbstractProcessor {
private List<PropertyDescriptor> properties;
private Set<Relationship> relationships;
- private static final String FEATURE_PREFIX = "http://xml.org/sax/features/";
- public static final String ENABLE_NAMESPACES_FEATURE = FEATURE_PREFIX + "namespaces";
- public static final String ENABLE_NAMESPACE_PREFIXES_FEATURE = FEATURE_PREFIX + "namespace-prefixes";
- private static final SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
-
- static {
- saxParserFactory.setNamespaceAware(true);
- try {
- saxParserFactory.setFeature(ENABLE_NAMESPACES_FEATURE, true);
- saxParserFactory.setFeature(ENABLE_NAMESPACE_PREFIXES_FEATURE, true);
- } catch (Exception e) {
- final Logger staticLogger = LoggerFactory.getLogger(SplitXml.class);
- staticLogger.warn("Unable to configure SAX Parser to make namespaces available", e);
- }
- }
-
@Override
protected void init(final ProcessorInitializationContext context) {
final List<PropertyDescriptor> properties = new ArrayList<>();
@@ -169,7 +150,7 @@ public class SplitXml extends AbstractProcessor {
final AtomicInteger numberOfRecords = new AtomicInteger(0);
final XmlSplitterSaxParser parser = new XmlSplitterSaxParser(xmlTree -> {
FlowFile split = session.create(original);
- split = session.write(split, out -> out.write(xmlTree.getBytes("UTF-8")));
+ split = session.write(split, out -> out.write(xmlTree.getBytes(StandardCharsets.UTF_8)));
split = session.putAttribute(split, FRAGMENT_ID.key(), fragmentIdentifier);
split = session.putAttribute(split, FRAGMENT_INDEX.key(), Integer.toString(numberOfRecords.getAndIncrement()));
split = session.putAttribute(split, SEGMENT_ORIGINAL_FILENAME.key(), split.getAttribute(CoreAttributes.FILENAME.key()));
@@ -180,10 +161,11 @@ public class SplitXml extends AbstractProcessor {
session.read(original, rawIn -> {
try (final InputStream in = new java.io.BufferedInputStream(rawIn)) {
try {
- final XMLReader reader = XmlUtils.createSafeSaxReader(saxParserFactory, parser);
- reader.parse(new InputSource(in));
- } catch (final ParserConfigurationException | SAXException e) {
- logger.error("Unable to parse {} due to {}", new Object[]{original, e});
+ final StandardInputSourceParser inputSourceParser = new StandardInputSourceParser();
+ inputSourceParser.setNamespaceAware(true);
+ inputSourceParser.parse(new InputSource(in), parser);
+ } catch (final ProcessingException e) {
+ logger.error("Parsing failed {}", original, e);
failed.set(true);
}
}
@@ -200,7 +182,7 @@ public class SplitXml extends AbstractProcessor {
final FlowFile originalToTransfer = copyAttributesToOriginal(session, original, fragmentIdentifier, numberOfRecords.get());
session.transfer(originalToTransfer, REL_ORIGINAL);
- logger.info("Split {} into {} FlowFiles", new Object[]{originalToTransfer, splits.size()});
+ logger.info("Split {} into {} FlowFiles", originalToTransfer, splits.size());
}
}
@@ -211,7 +193,7 @@ public class SplitXml extends AbstractProcessor {
private final int splitDepth;
private final StringBuilder sb = new StringBuilder(XML_PROLOGUE);
private int depth = 0;
- private Map<String, String> prefixMap = new TreeMap<>();
+ private final Map<String, String> prefixMap = new TreeMap<>();
public XmlSplitterSaxParser(XmlElementNotifier notifier, int splitDepth) {
this.notifier = notifier;
@@ -252,11 +234,11 @@ public class SplitXml extends AbstractProcessor {
}
@Override
- public void endDocument() throws SAXException {
+ public void endDocument() {
}
@Override
- public void endElement(String uri, String localName, String qName) throws SAXException {
+ public void endElement(String uri, String localName, String qName) {
// We have finished processing this element. Decrement the depth.
int newDepth = --depth;
@@ -279,16 +261,16 @@ public class SplitXml extends AbstractProcessor {
}
@Override
- public void endPrefixMapping(String prefix) throws SAXException {
+ public void endPrefixMapping(String prefix) {
prefixMap.remove(prefixToNamespace(prefix));
}
@Override
- public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
+ public void ignorableWhitespace(char[] ch, int start, int length) {
}
@Override
- public void processingInstruction(String target, String data) throws SAXException {
+ public void processingInstruction(String target, String data) {
}
@Override
@@ -296,15 +278,15 @@ public class SplitXml extends AbstractProcessor {
}
@Override
- public void skippedEntity(String name) throws SAXException {
+ public void skippedEntity(String name) {
}
@Override
- public void startDocument() throws SAXException {
+ public void startDocument() {
}
@Override
- public void startElement(final String uri, final String localName, final String qName, final Attributes atts) throws SAXException {
+ public void startElement(final String uri, final String localName, final String qName, final Attributes atts) {
// Increment the current depth because start a new XML element.
int newDepth = ++depth;
// Output the element and its attributes if it is
@@ -343,7 +325,7 @@ public class SplitXml extends AbstractProcessor {
}
@Override
- public void startPrefixMapping(String prefix, String uri) throws SAXException {
+ public void startPrefixMapping(String prefix, String uri) {
final String ns = prefixToNamespace(prefix);
prefixMap.put(ns, uri);
}
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/TransformXml.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/TransformXml.java
index 49220a9e13..79a345ef8f 100644
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/TransformXml.java
+++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/TransformXml.java
@@ -48,11 +48,12 @@ import org.apache.nifi.processor.ProcessorInitializationContext;
import org.apache.nifi.processor.Relationship;
import org.apache.nifi.processor.exception.ProcessException;
import org.apache.nifi.processor.util.StandardValidators;
-import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.util.StopWatch;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLStreamReaderProvider;
import javax.xml.XMLConstants;
-import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
@@ -363,10 +364,11 @@ public class TransformXml extends AbstractProcessor {
}
private Source getSecureSource(final StreamSource streamSource) throws TransformerConfigurationException {
+ final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
try {
- final XMLStreamReader streamReader = XmlUtils.createSafeReader(streamSource);
+ final XMLStreamReader streamReader = provider.getStreamReader(streamSource);
return new StAXSource(streamReader);
- } catch (final XMLStreamException e) {
+ } catch (final ProcessingException e) {
throw new TransformerConfigurationException("XSLT Source Stream Reader creation failed", e);
}
}
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ValidateXml.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ValidateXml.java
index b7184d4f06..0ae33391d8 100644
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ValidateXml.java
+++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/ValidateXml.java
@@ -39,19 +39,22 @@ import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.processor.ProcessSession;
import org.apache.nifi.processor.ProcessorInitializationContext;
import org.apache.nifi.processor.Relationship;
-import org.apache.nifi.processor.io.InputStreamCallback;
import org.apache.nifi.processor.util.StandardValidators;
-import org.apache.nifi.security.xml.SafeXMLConfiguration;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLStreamReaderProvider;
+import org.apache.nifi.xml.processing.validation.StandardSchemaValidator;
+import org.apache.nifi.xml.processing.validation.SchemaValidator;
import org.xml.sax.SAXException;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.Source;
+import javax.xml.transform.stax.StAXSource;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
-import javax.xml.validation.Validator;
import java.io.ByteArrayInputStream;
-import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.charset.StandardCharsets;
@@ -110,6 +113,10 @@ public class ValidateXml extends AbstractProcessor {
private static final String SCHEMA_LANGUAGE = "http://www.w3.org/2001/XMLSchema";
+ private static final SchemaValidator SCHEMA_VALIDATOR = new StandardSchemaValidator();
+
+ private static final XMLStreamReaderProvider READER_PROVIDER = new StandardXMLStreamReaderProvider();
+
private List<PropertyDescriptor> properties;
private Set<Relationship> relationships;
private final AtomicReference<Schema> schemaRef = new AtomicReference<>();
@@ -156,41 +163,25 @@ public class ValidateXml extends AbstractProcessor {
return;
}
- final Schema schema = schemaRef.get();
- final Validator validator = schema == null ? null : schema.newValidator();
final ComponentLog logger = getLogger();
final boolean attributeContainsXML = context.getProperty(XML_SOURCE_ATTRIBUTE).isSet();
for (FlowFile flowFile : flowFiles) {
final AtomicBoolean valid = new AtomicBoolean(true);
final AtomicReference<Exception> exception = new AtomicReference<>(null);
- SafeXMLConfiguration safeXMLConfiguration = new SafeXMLConfiguration();
- safeXMLConfiguration.setValidating(false);
try {
- DocumentBuilder docBuilder = safeXMLConfiguration.createDocumentBuilder();
-
if (attributeContainsXML) {
// If XML source attribute is set, validate attribute value
String xml = flowFile.getAttribute(context.getProperty(XML_SOURCE_ATTRIBUTE).evaluateAttributeExpressions().getValue());
- ByteArrayInputStream bais = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8));
- validate(validator, docBuilder, bais);
+ validate(inputStream);
} else {
// If XML source attribute is not set, validate flowfile content
- session.read(flowFile, new InputStreamCallback() {
- @Override
- public void process(final InputStream in) throws IOException {
- try {
- validate(validator, docBuilder, in);
- } catch (final IllegalArgumentException | SAXException e) {
- valid.set(false);
- exception.set(e);
- }
- }
- });
+ session.read(flowFile, inputStream -> validate(inputStream));
}
- } catch (final IllegalArgumentException | SAXException | ParserConfigurationException | IOException e) {
+ } catch (final RuntimeException e) {
valid.set(false);
exception.set(e);
}
@@ -218,13 +209,23 @@ public class ValidateXml extends AbstractProcessor {
}
}
- private void validate(final Validator validator, final DocumentBuilder docBuilder, final InputStream in) throws IllegalArgumentException, SAXException, IOException {
- if (validator != null) {
- // If schema is provided, validator will be non-null
- validator.validate(new StreamSource(in));
+ private void validate(final InputStream in) {
+ final Schema schema = schemaRef.get();
+ if (schema == null) {
+ // Parse Document without schema validation
+ final XMLStreamReader reader = READER_PROVIDER.getStreamReader(new StreamSource(in));
+ try {
+ while (reader.hasNext()) {
+ reader.next();
+ }
+ } catch (final XMLStreamException e) {
+ throw new ProcessingException("Reading stream failed", e);
+ }
} else {
- // Only verify that the XML is well-formed; no schema check
- docBuilder.parse(in);
+ final XMLStreamReaderProvider readerProvider = new StandardXMLStreamReaderProvider();
+ final XMLStreamReader reader = readerProvider.getStreamReader(new StreamSource(in));
+ final Source source = new StAXSource(reader);
+ SCHEMA_VALIDATOR.validate(schema, source);
}
}
}
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/DocumentReaderCallback.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/DocumentReaderCallback.java
index 89d1485c61..f2230e2c3f 100644
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/DocumentReaderCallback.java
+++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/util/DocumentReaderCallback.java
@@ -18,12 +18,10 @@ package org.apache.nifi.processors.standard.util;
import java.io.IOException;
import java.io.InputStream;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.ParserConfigurationException;
import org.apache.nifi.processor.io.InputStreamCallback;
-import org.apache.nifi.security.xml.XmlUtils;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.w3c.dom.Document;
-import org.xml.sax.SAXException;
public class DocumentReaderCallback implements InputStreamCallback {
@@ -42,10 +40,11 @@ public class DocumentReaderCallback implements InputStreamCallback {
@Override
public void process(final InputStream stream) throws IOException {
try {
- DocumentBuilder builder = XmlUtils.createSafeDocumentBuilder(isNamespaceAware);
- document = builder.parse(stream);
- } catch (ParserConfigurationException | SAXException pce) {
- throw new IOException(pce.getLocalizedMessage(), pce);
+ final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
+ documentProvider.setNamespaceAware(isNamespaceAware);
+ document = documentProvider.parse(stream);
+ } catch (final ProcessingException e) {
+ throw new IOException(e.getLocalizedMessage(), e);
}
}
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/xml/DocumentTypeAllowedDocumentProvider.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/xml/DocumentTypeAllowedDocumentProvider.java
new file mode 100644
index 0000000000..be54f7a701
--- /dev/null
+++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/xml/DocumentTypeAllowedDocumentProvider.java
@@ -0,0 +1,34 @@
+/*
+ * 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.nifi.processors.standard.xml;
+
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
+
+/**
+ * Document Provider implementation that allows local Document Type Declarations
+ */
+public class DocumentTypeAllowedDocumentProvider extends StandardDocumentProvider {
+ /**
+ * Enable Document Type Declaration through disabling disallow configuration
+ *
+ * @return Disallow Disabled
+ */
+ @Override
+ protected boolean isDisallowDocumentTypeDeclaration() {
+ return false;
+ }
+}
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEvaluateXPath.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEvaluateXPath.java
index 98899bbe14..95d366a859 100644
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEvaluateXPath.java
+++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEvaluateXPath.java
@@ -16,19 +16,19 @@
*/
package org.apache.nifi.processors.standard;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
-import javax.xml.xpath.XPathFactoryConfigurationException;
-
import org.apache.nifi.util.MockFlowFile;
import org.apache.nifi.util.TestRunner;
import org.apache.nifi.util.TestRunners;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
public class TestEvaluateXPath {
@@ -37,7 +37,7 @@ public class TestEvaluateXPath {
private static final Path XML_SNIPPET_NONEXISTENT_DOCTYPE = Paths.get("src/test/resources/TestXml/xml-snippet-external-doctype.xml");
@Test
- public void testAsAttribute() throws XPathFactoryConfigurationException, IOException {
+ public void testAsAttribute() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXPath());
testRunner.setProperty(EvaluateXPath.DESTINATION, EvaluateXPath.DESTINATION_ATTRIBUTE);
testRunner.setProperty("xpath.result1", "/");
@@ -53,7 +53,7 @@ public class TestEvaluateXPath {
}
@Test
- public void testCheckIfElementExists() throws XPathFactoryConfigurationException, IOException {
+ public void testCheckIfElementExists() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXPath());
testRunner.setProperty(EvaluateXPath.DESTINATION, EvaluateXPath.DESTINATION_ATTRIBUTE);
testRunner.setProperty("xpath.result1", "/");
@@ -71,7 +71,7 @@ public class TestEvaluateXPath {
}
@Test
- public void testUnmatched() throws XPathFactoryConfigurationException, IOException {
+ public void testUnmatched() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXPath());
testRunner.setProperty(EvaluateXPath.DESTINATION, EvaluateXPath.DESTINATION_CONTENT);
testRunner.setProperty("xpath.result.exist.2", "/*:bundle/node2");
@@ -83,7 +83,7 @@ public class TestEvaluateXPath {
testRunner.getFlowFilesForRelationship(EvaluateXPath.REL_NO_MATCH).get(0).assertContentEquals(XML_SNIPPET);
}
- @Test(expected = java.lang.AssertionError.class)
+ @Test
public void testMultipleXPathForContent() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXPath());
testRunner.setProperty(EvaluateXPath.DESTINATION, EvaluateXPath.DESTINATION_CONTENT);
@@ -92,11 +92,12 @@ public class TestEvaluateXPath {
testRunner.setProperty("some.property.2", "/*:bundle/node/subNode[2]");
testRunner.enqueue(XML_SNIPPET);
- testRunner.run();
+
+ assertThrows(AssertionError.class, testRunner::run);
}
@Test
- public void testWriteToContent() throws XPathFactoryConfigurationException, IOException {
+ public void testWriteToContent() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXPath());
testRunner.setProperty(EvaluateXPath.DESTINATION, EvaluateXPath.DESTINATION_CONTENT);
testRunner.setProperty("some.property", "/*:bundle/node/subNode[1]");
@@ -107,13 +108,13 @@ public class TestEvaluateXPath {
testRunner.assertAllFlowFilesTransferred(EvaluateXPath.REL_MATCH, 1);
final MockFlowFile out = testRunner.getFlowFilesForRelationship(EvaluateXPath.REL_MATCH).get(0);
final byte[] outData = testRunner.getContentAsByteArray(out);
- final String outXml = new String(outData, "UTF-8");
+ final String outXml = new String(outData, StandardCharsets.UTF_8);
assertTrue(outXml.contains("subNode"));
assertTrue(outXml.contains("Hello"));
}
@Test
- public void testFailureIfContentMatchesMultipleNodes() throws XPathFactoryConfigurationException, IOException {
+ public void testFailureIfContentMatchesMultipleNodes() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXPath());
testRunner.setProperty(EvaluateXPath.DESTINATION, EvaluateXPath.DESTINATION_CONTENT);
testRunner.setProperty("some.property", "/*:bundle/node/subNode");
@@ -125,7 +126,7 @@ public class TestEvaluateXPath {
}
@Test
- public void testWriteStringToContent() throws XPathFactoryConfigurationException, IOException {
+ public void testWriteStringToContent() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXPath());
testRunner.setProperty(EvaluateXPath.DESTINATION, EvaluateXPath.DESTINATION_CONTENT);
testRunner.setProperty(EvaluateXPath.RETURN_TYPE, EvaluateXPath.RETURN_TYPE_STRING);
@@ -136,13 +137,11 @@ public class TestEvaluateXPath {
testRunner.assertAllFlowFilesTransferred(EvaluateXPath.REL_MATCH, 1);
final MockFlowFile out = testRunner.getFlowFilesForRelationship(EvaluateXPath.REL_MATCH).get(0);
- final byte[] outData = testRunner.getContentAsByteArray(out);
- final String outXml = new String(outData, "UTF-8");
- assertTrue(outXml.trim().equals("Hello"));
+ out.assertContentEquals("Hello");
}
@Test
- public void testWriteNodeSetToAttribute() throws XPathFactoryConfigurationException, IOException {
+ public void testWriteNodeSetToAttribute() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXPath());
testRunner.setProperty(EvaluateXPath.DESTINATION, EvaluateXPath.DESTINATION_ATTRIBUTE);
testRunner.setProperty(EvaluateXPath.RETURN_TYPE, EvaluateXPath.RETURN_TYPE_NODESET);
@@ -159,7 +158,7 @@ public class TestEvaluateXPath {
}
@Test
- public void testSuccessForEmbeddedDocTypeValidation() throws XPathFactoryConfigurationException, IOException {
+ public void testSuccessForEmbeddedDocTypeValidation() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXPath());
testRunner.setProperty(EvaluateXPath.DESTINATION, EvaluateXPath.DESTINATION_CONTENT);
testRunner.setProperty(EvaluateXPath.RETURN_TYPE, EvaluateXPath.RETURN_TYPE_STRING);
@@ -171,13 +170,11 @@ public class TestEvaluateXPath {
testRunner.assertAllFlowFilesTransferred(EvaluateXPath.REL_MATCH, 1);
final MockFlowFile out = testRunner.getFlowFilesForRelationship(EvaluateXPath.REL_MATCH).get(0);
- final byte[] outData = testRunner.getContentAsByteArray(out);
- final String outXml = new String(outData, "UTF-8");
- assertTrue(outXml.trim().equals("Hello"));
+ out.assertContentEquals("Hello");
}
@Test
- public void testSuccessForEmbeddedDocTypeValidationDisabled() throws XPathFactoryConfigurationException, IOException {
+ public void testFailureForEmbeddedDocTypeValidationDisabled() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXPath());
testRunner.setProperty(EvaluateXPath.DESTINATION, EvaluateXPath.DESTINATION_CONTENT);
testRunner.setProperty(EvaluateXPath.RETURN_TYPE, EvaluateXPath.RETURN_TYPE_STRING);
@@ -187,15 +184,11 @@ public class TestEvaluateXPath {
testRunner.enqueue(XML_SNIPPET_EMBEDDED_DOCTYPE);
testRunner.run();
- testRunner.assertAllFlowFilesTransferred(EvaluateXPath.REL_MATCH, 1);
- final MockFlowFile out = testRunner.getFlowFilesForRelationship(EvaluateXPath.REL_MATCH).get(0);
- final byte[] outData = testRunner.getContentAsByteArray(out);
- final String outXml = new String(outData, "UTF-8");
- assertTrue(outXml.trim().equals("Hello"));
+ testRunner.assertAllFlowFilesTransferred(EvaluateXPath.REL_FAILURE, 1);
}
@Test
- public void testFailureForExternalDocTypeWithDocTypeValidationEnabled() throws XPathFactoryConfigurationException, IOException {
+ public void testFailureForExternalDocTypeWithDocTypeValidationEnabled() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXPath());
testRunner.setProperty(EvaluateXPath.DESTINATION, EvaluateXPath.DESTINATION_CONTENT);
testRunner.setProperty(EvaluateXPath.RETURN_TYPE, EvaluateXPath.RETURN_TYPE_STRING);
@@ -208,7 +201,7 @@ public class TestEvaluateXPath {
}
@Test
- public void testSuccessForExternalDocTypeWithDocTypeValidationDisabled() throws XPathFactoryConfigurationException, IOException {
+ public void testFailureForExternalDocTypeWithDocTypeValidationDisabled() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXPath());
testRunner.setProperty(EvaluateXPath.DESTINATION, EvaluateXPath.DESTINATION_CONTENT);
testRunner.setProperty(EvaluateXPath.RETURN_TYPE, EvaluateXPath.RETURN_TYPE_STRING);
@@ -218,11 +211,6 @@ public class TestEvaluateXPath {
testRunner.enqueue(XML_SNIPPET_NONEXISTENT_DOCTYPE);
testRunner.run();
- testRunner.assertAllFlowFilesTransferred(EvaluateXPath.REL_MATCH, 1);
- final MockFlowFile out = testRunner.getFlowFilesForRelationship(EvaluateXPath.REL_MATCH).get(0);
- final byte[] outData = testRunner.getContentAsByteArray(out);
- final String outXml = new String(outData, "UTF-8");
- assertTrue(outXml.trim().equals("Hello"));
+ testRunner.assertAllFlowFilesTransferred(EvaluateXPath.REL_FAILURE, 1);
}
-
}
diff --git a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEvaluateXQuery.java b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEvaluateXQuery.java
index 05fe9c278f..7282f07244 100644
--- a/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEvaluateXQuery.java
+++ b/nifi-nar-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestEvaluateXQuery.java
@@ -16,15 +16,18 @@
*/
package org.apache.nifi.processors.standard;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -32,13 +35,12 @@ import java.util.Map.Entry;
import java.util.Properties;
import javax.xml.transform.OutputKeys;
-import javax.xml.xpath.XPathFactoryConfigurationException;
import org.apache.nifi.util.MockFlowFile;
import org.apache.nifi.util.TestRunner;
import org.apache.nifi.util.TestRunners;
-import org.junit.Test;
+import org.junit.jupiter.api.Test;
public class TestEvaluateXQuery {
@@ -52,16 +54,15 @@ public class TestEvaluateXQuery {
private static final boolean[] booleans = {true, false};
@Test
- public void testSetTransformerProperties() throws Exception {
-
- for (int i = 0; i < methods.length; i++) {
- for (int j = 0; j < booleans.length; j++) {
- for (int k = 0; k < booleans.length; k++) {
- Properties props = EvaluateXQuery.getTransformerProperties(methods[i], booleans[j], booleans[k]);
+ public void testSetTransformerProperties() {
+ for (final String method : methods) {
+ for (final boolean indent : booleans) {
+ for (final boolean omitDeclaration : booleans) {
+ Properties props = EvaluateXQuery.getTransformerProperties(method, indent, omitDeclaration);
assertEquals(3, props.size());
- assertEquals(methods[i], props.getProperty(OutputKeys.METHOD));
- assertEquals(booleans[j] ? "yes" : "no", props.getProperty(OutputKeys.INDENT));
- assertEquals(booleans[k] ? "yes" : "no", props.getProperty(OutputKeys.OMIT_XML_DECLARATION));
+ assertEquals(method, props.getProperty(OutputKeys.METHOD));
+ assertEquals(indent ? "yes" : "no", props.getProperty(OutputKeys.INDENT));
+ assertEquals(omitDeclaration ? "yes" : "no", props.getProperty(OutputKeys.OMIT_XML_DECLARATION));
}
}
}
@@ -75,20 +76,20 @@ public class TestEvaluateXQuery {
final String singleElementNodeQuery = "//fruit[1]";
final String singleTextNodeQuery = "//fruit[1]/name/text()";
- for (int i = 0; i < methods.length; i++) {
- for (int j = 0; j < booleans.length; j++) {
- for (int k = 0; k < booleans.length; k++) {
- formattedResults = getFormattedResult(XML_SNIPPET, atomicQuery, methods[i], booleans[j], booleans[k]);
+ for (final String method : methods) {
+ for (final boolean indent : booleans) {
+ for (final boolean omitDeclaration : booleans) {
+ formattedResults = getFormattedResult(XML_SNIPPET, atomicQuery, method, indent, omitDeclaration);
assertEquals(1, formattedResults.size());
assertEquals("7", formattedResults.get(0));
}
}
}
- for (int i = 0; i < methods.length; i++) {
- for (int j = 0; j < booleans.length; j++) {
- for (int k = 0; k < booleans.length; k++) {
- formattedResults = getFormattedResult(XML_SNIPPET, singleTextNodeQuery, methods[i], booleans[j], booleans[k]);
+ for (final String method : methods) {
+ for (final boolean indent : booleans) {
+ for (final boolean omitDeclaration : booleans) {
+ formattedResults = getFormattedResult(XML_SNIPPET, singleTextNodeQuery, method, indent, omitDeclaration);
assertEquals(1, formattedResults.size());
assertEquals("apple", formattedResults.get(0));
}
@@ -161,7 +162,6 @@ public class TestEvaluateXQuery {
List<MockFlowFile> resultFlowFiles;
List<String> resultStrings = new ArrayList<>();
- runnerProps.clear();
runnerProps.put(EvaluateXQuery.DESTINATION.getName(), EvaluateXQuery.DESTINATION_CONTENT);
runnerProps.put(EvaluateXQuery.XML_OUTPUT_METHOD.getName(), method);
runnerProps.put(EvaluateXQuery.XML_OUTPUT_INDENT.getName(), Boolean.toString(indent));
@@ -169,45 +169,44 @@ public class TestEvaluateXQuery {
runnerProps.put("xquery", xQuery);
resultFlowFiles = runXquery(xml, runnerProps);
- for (int i = 0; i < resultFlowFiles.size(); i++) {
- final MockFlowFile out = resultFlowFiles.get(i);
- final byte[] outData = out.toByteArray();
- final String outXml = new String(outData, "UTF-8");
+ for (final MockFlowFile flowFile : resultFlowFiles) {
+ final byte[] outData = flowFile.toByteArray();
+ final String outXml = new String(outData, StandardCharsets.UTF_8);
resultStrings.add(outXml);
}
return resultStrings;
}
- @Test(expected = java.lang.AssertionError.class)
- public void testBadXQuery() throws Exception {
- doXqueryTest(XML_SNIPPET, "counttttttt(*:fruitbasket/fruit)", Arrays.asList("7"));
+ @Test
+ public void testBadXQuery() {
+ assertThrows(AssertionError.class, () -> doXqueryTest(XML_SNIPPET, "counttttttt(*:fruitbasket/fruit)", Collections.singletonList("7")));
}
@Test
public void testXQueries() throws Exception {
/* count matches */
- doXqueryTest(XML_SNIPPET, "count(*:fruitbasket/fruit)", Arrays.asList("7"));
- doXqueryTest(XML_SNIPPET, "count(//fruit)", Arrays.asList("7"));
+ doXqueryTest(XML_SNIPPET, "count(*:fruitbasket/fruit)", Collections.singletonList("7"));
+ doXqueryTest(XML_SNIPPET, "count(//fruit)", Collections.singletonList("7"));
/* Using a namespace */
- doXqueryTest(XML_SNIPPET, "declare namespace fb = \"http://namespace/1\"; count(fb:fruitbasket/fruit)", Arrays.asList("7"));
+ doXqueryTest(XML_SNIPPET, "declare namespace fb = \"http://namespace/1\"; count(fb:fruitbasket/fruit)", Collections.singletonList("7"));
/* determine if node exists */
- doXqueryTest(XML_SNIPPET, "boolean(//fruit[1])", Arrays.asList("true"));
- doXqueryTest(XML_SNIPPET, "boolean(//fruit[100])", Arrays.asList("false"));
+ doXqueryTest(XML_SNIPPET, "boolean(//fruit[1])", Collections.singletonList("true"));
+ doXqueryTest(XML_SNIPPET, "boolean(//fruit[100])", Collections.singletonList("false"));
/* XML first match */
- doXqueryTest(XML_SNIPPET, "//fruit[1]", Arrays.asList(
+ doXqueryTest(XML_SNIPPET, "//fruit[1]", Collections.singletonList(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><fruit xmlns:ns=\"http://namespace/1\" taste=\"crisp\"><!-- Apples are my favorite --><name>apple</name><color>red</color></fruit>"));
/* XML last match */
- doXqueryTest(XML_SNIPPET, "//fruit[count(//fruit)]", Arrays.asList(
+ doXqueryTest(XML_SNIPPET, "//fruit[count(//fruit)]", Collections.singletonList(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><fruit xmlns:ns=\"http://namespace/1\"><name>none</name><color/></fruit>"));
/* XML first match wrapped */
- doXqueryTest(XML_SNIPPET, "<wrap>{//fruit[1]}</wrap>", Arrays.asList(
+ doXqueryTest(XML_SNIPPET, "<wrap>{//fruit[1]}</wrap>", Collections.singletonList(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><wrap><fruit xmlns:ns=\"http://namespace/1\" taste=\"crisp\"><!-- Apples are my favorite --><name>apple</name><color>red</color></fruit></wrap>"));
/* XML all matches (multiple results) */
@@ -221,7 +220,7 @@ public class TestEvaluateXQuery {
"<?xml version=\"1.0\" encoding=\"UTF-8\"?><fruit xmlns:ns=\"http://namespace/1\"><name>none</name><color/></fruit>"));
/* XML all matches wrapped (one result)*/
- doXqueryTest(XML_SNIPPET, "<wrap>{//fruit}</wrap>", Arrays.asList(
+ doXqueryTest(XML_SNIPPET, "<wrap>{//fruit}</wrap>", Collections.singletonList(
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+ "<wrap>"
+ "<fruit xmlns:ns=\"http://namespace/1\" taste=\"crisp\"><!-- Apples are my favorite --><name>apple</name><color>red</color></fruit>"
@@ -237,18 +236,18 @@ public class TestEvaluateXQuery {
doXqueryTest(XML_SNIPPET, "for $x in //fruit return $x/name/text()", Arrays.asList(fruitNames));
/* String first match fruit name (XPath)*/
- doXqueryTest(XML_SNIPPET, "//fruit[1]/name/text()", Arrays.asList("apple"));
+ doXqueryTest(XML_SNIPPET, "//fruit[1]/name/text()", Collections.singletonList("apple"));
/* String first match fruit color (XPath)*/
- doXqueryTest(XML_SNIPPET, "//fruit[1]/color/text()", Arrays.asList("red"));
+ doXqueryTest(XML_SNIPPET, "//fruit[1]/color/text()", Collections.singletonList("red"));
/* String first match fruit name (XQuery)*/
doXqueryTest(XML_SNIPPET, "for $x in //fruit[1] return string-join(($x/name/text() , $x/color/text()), ' - ')",
- Arrays.asList("apple - red"));
+ Collections.singletonList("apple - red"));
/* String first match fruit & color (one result)*/
doXqueryTest(XML_SNIPPET, "for $x in //fruit[1] return string-join(($x/name/text() , $x/color/text()), ' - ')",
- Arrays.asList("apple - red"));
+ Collections.singletonList("apple - red"));
/* String all matches fruit & color (multiple results)*/
doXqueryTest(XML_SNIPPET, "for $x in //fruit return string-join(($x/name/text() , $x/color/text()), ' - ')",
@@ -263,7 +262,7 @@ public class TestEvaluateXQuery {
/* String all matches fruit & color (single, newline delimited result)*/
doXqueryTest(XML_SNIPPET, "string-join((for $y in (for $x in //fruit return string-join(($x/name/text() , $x/color/text()), ' - ')) return $y), '\n')",
- Arrays.asList(
+ Collections.singletonList(
"apple - red\n"
+ "apple - green\n"
+ "banana - yellow\n"
@@ -274,7 +273,7 @@ public class TestEvaluateXQuery {
/* String all matches fruit & color using "let" (single, newline delimited result)*/
doXqueryTest(XML_SNIPPET, "string-join((for $y in (for $x in //fruit let $d := string-join(($x/name/text() , $x/color/text()), ' - ') return $d) return $y), '\n')",
- Arrays.asList(
+ Collections.singletonList(
"apple - red\n"
+ "apple - green\n"
+ "banana - yellow\n"
@@ -285,25 +284,25 @@ public class TestEvaluateXQuery {
/* String all matches name only, comma delimited (one result)*/
doXqueryTest(XML_SNIPPET, "string-join((for $x in //fruit return $x/name/text()), ', ')",
- Arrays.asList("apple, apple, banana, orange, blueberry, raspberry, none"));
+ Collections.singletonList("apple, apple, banana, orange, blueberry, raspberry, none"));
/* String all matches color and name, comma delimited (one result)*/
doXqueryTest(XML_SNIPPET, "string-join((for $y in (for $x in //fruit return string-join(($x/color/text() , $x/name/text()), ' ')) return $y), ', ')",
- Arrays.asList("red apple, green apple, yellow banana, orange orange, blue blueberry, red raspberry, none"));
+ Collections.singletonList("red apple, green apple, yellow banana, orange orange, blue blueberry, red raspberry, none"));
/* String all matches color and name, comma delimited using let(one result)*/
doXqueryTest(XML_SNIPPET, "string-join((for $y in (for $x in //fruit let $d := string-join(($x/color/text() , $x/name/text()), ' ') return $d) return $y), ', ')",
- Arrays.asList("red apple, green apple, yellow banana, orange orange, blue blueberry, red raspberry, none"));
+ Collections.singletonList("red apple, green apple, yellow banana, orange orange, blue blueberry, red raspberry, none"));
/* Query for attribute */
- doXqueryTest(XML_SNIPPET, "string(//fruit[1]/@taste)", Arrays.asList("crisp"));
+ doXqueryTest(XML_SNIPPET, "string(//fruit[1]/@taste)", Collections.singletonList("crisp"));
/* Query for comment */
- doXqueryTest(XML_SNIPPET, "//fruit/comment()", Arrays.asList(" Apples are my favorite "));
+ doXqueryTest(XML_SNIPPET, "//fruit/comment()", Collections.singletonList(" Apples are my favorite "));
/* Query for processing instruction */
- doXqueryTest(XML_SNIPPET, "//processing-instruction()[name()='xml-stylesheet']", Arrays.asList("type=\"text/xsl\" href=\"foo.xsl\""));
+ doXqueryTest(XML_SNIPPET, "//processing-instruction()[name()='xml-stylesheet']", Collections.singletonList("type=\"text/xsl\" href=\"foo.xsl\""));
}
@@ -313,50 +312,44 @@ public class TestEvaluateXQuery {
List<MockFlowFile> resultFlowFiles;
// test read from content, write to attribute
- {
- runnerProps.clear();
- runnerProps.put(EvaluateXQuery.DESTINATION.getName(), EvaluateXQuery.DESTINATION_ATTRIBUTE);
- runnerProps.put("xquery", xQuery);
- resultFlowFiles = runXquery(xml, runnerProps);
+ runnerProps.put(EvaluateXQuery.DESTINATION.getName(), EvaluateXQuery.DESTINATION_ATTRIBUTE);
+ runnerProps.put("xquery", xQuery);
+ resultFlowFiles = runXquery(xml, runnerProps);
- assertEquals(1, resultFlowFiles.size());
+ assertEquals(1, resultFlowFiles.size());
- final MockFlowFile out = resultFlowFiles.get(0);
+ final MockFlowFile out = resultFlowFiles.get(0);
- for (int i = 0; i < expectedResults.size(); i++) {
- String key = "xquery";
- if (expectedResults.size() > 1) {
- key += "." + ((int) i + 1);
- }
- final String actual = out.getAttribute(key).replaceAll(">\\s+<", "><");
- final String expected = expectedResults.get(i).replaceAll(">\\s+<", "><");
- assertEquals(expected, actual);
+ for (int i = 0; i < expectedResults.size(); i++) {
+ String key = "xquery";
+ if (expectedResults.size() > 1) {
+ key += "." + (i + 1);
}
+ final String actual = out.getAttribute(key).replaceAll(">\\s+<", "><");
+ final String expected = expectedResults.get(i).replaceAll(">\\s+<", "><");
+ assertEquals(expected, actual);
}
// test read from content, write to content
- {
- runnerProps.clear();
- runnerProps.put(EvaluateXQuery.DESTINATION.getName(), EvaluateXQuery.DESTINATION_CONTENT);
- runnerProps.put("xquery", xQuery);
- resultFlowFiles = runXquery(xml, runnerProps);
+ runnerProps.clear();
+ runnerProps.put(EvaluateXQuery.DESTINATION.getName(), EvaluateXQuery.DESTINATION_CONTENT);
+ runnerProps.put("xquery", xQuery);
+ resultFlowFiles = runXquery(xml, runnerProps);
- assertEquals(expectedResults.size(), resultFlowFiles.size());
+ assertEquals(expectedResults.size(), resultFlowFiles.size());
- for (int i = 0; i < resultFlowFiles.size(); i++) {
+ for (int i = 0; i < resultFlowFiles.size(); i++) {
- final MockFlowFile out = resultFlowFiles.get(i);
- final byte[] outData = out.toByteArray();
- final String outXml = new String(outData, "UTF-8").replaceAll(">\\s+<", "><");
- final String actual = outXml;
- final String expected = expectedResults.get(i).replaceAll(">\\s+<", "><");
- assertEquals(expected, actual);
- }
+ final MockFlowFile resultFlowFile = resultFlowFiles.get(i);
+ final byte[] outData = resultFlowFile.toByteArray();
+ final String outXml = new String(outData, StandardCharsets.UTF_8).replaceAll(">\\s+<", "><");
+ final String expected = expectedResults.get(i).replaceAll(">\\s+<", "><");
+ assertEquals(expected, outXml);
}
}
private List<MockFlowFile> runXquery(Path xml, Map<String, String> runnerProps) throws Exception {
- return runXquery(xml, runnerProps, new HashMap<String, String>());
+ return runXquery(xml, runnerProps, new HashMap<>());
}
private List<MockFlowFile> runXquery(Path xml, Map<String, String> runnerProps, Map<String, String> flowFileAttributes) throws Exception {
@@ -376,7 +369,7 @@ public class TestEvaluateXQuery {
}
@Test
- public void testRootPath() throws XPathFactoryConfigurationException, IOException {
+ public void testRootPath() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_ATTRIBUTE);
testRunner.setProperty("xquery.result1", "/");
@@ -387,13 +380,13 @@ public class TestEvaluateXQuery {
testRunner.assertAllFlowFilesTransferred(EvaluateXQuery.REL_MATCH, 1);
final MockFlowFile out = testRunner.getFlowFilesForRelationship(EvaluateXQuery.REL_MATCH).get(0);
final String attributeString = out.getAttribute("xquery.result1").replaceAll(">\\s+<", "><");
- final String xmlSnippetString = new String(Files.readAllBytes(XML_SNIPPET), "UTF-8").replaceAll(">\\s+<", "><");
+ final String xmlSnippetString = new String(Files.readAllBytes(XML_SNIPPET), StandardCharsets.UTF_8).replaceAll(">\\s+<", "><");
assertEquals(xmlSnippetString, attributeString);
}
@Test
- public void testCheckIfElementExists() throws XPathFactoryConfigurationException, IOException {
+ public void testCheckIfElementExists() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_ATTRIBUTE);
testRunner.setProperty("xquery.result.exist.1", "boolean(/*:fruitbasket/fruit[1])");
@@ -409,7 +402,7 @@ public class TestEvaluateXQuery {
}
@Test
- public void testUnmatchedContent() throws XPathFactoryConfigurationException, IOException {
+ public void testUnmatchedContent() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_CONTENT);
testRunner.setProperty("xquery.result.exist.2", "/*:fruitbasket/node2");
@@ -422,7 +415,7 @@ public class TestEvaluateXQuery {
}
@Test
- public void testUnmatchedAttribute() throws XPathFactoryConfigurationException, IOException {
+ public void testUnmatchedAttribute() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_ATTRIBUTE);
testRunner.setProperty("xquery.result.exist.2", "/*:fruitbasket/node2");
@@ -437,7 +430,7 @@ public class TestEvaluateXQuery {
}
@Test
- public void testNoXQueryAttribute() throws XPathFactoryConfigurationException, IOException {
+ public void testNoXQueryAttribute() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_ATTRIBUTE);
@@ -448,17 +441,17 @@ public class TestEvaluateXQuery {
testRunner.getFlowFilesForRelationship(EvaluateXQuery.REL_NO_MATCH).get(0).assertContentEquals(XML_SNIPPET);
}
- @Test(expected = java.lang.AssertionError.class)
- public void testNoXQueryContent() throws XPathFactoryConfigurationException, IOException {
+ @Test
+ public void testNoXQueryContent() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_CONTENT);
testRunner.enqueue(XML_SNIPPET);
- testRunner.run();
+ assertThrows(AssertionError.class, testRunner::run);
}
@Test
- public void testOneMatchOneUnmatchAttribute() throws XPathFactoryConfigurationException, IOException {
+ public void testOneMatchOneUnmatchAttribute() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_ATTRIBUTE);
testRunner.setProperty("some.property", "//fruit/name/text()");
@@ -472,7 +465,7 @@ public class TestEvaluateXQuery {
final MockFlowFile out = testRunner.getFlowFilesForRelationship(EvaluateXQuery.REL_MATCH).get(0);
for (int i = 0; i < fruitNames.length; i++) {
- final String outXml = out.getAttribute("some.property." + ((int) i + 1));
+ final String outXml = out.getAttribute("some.property." + (i + 1));
assertEquals(fruitNames[i], outXml.trim());
}
@@ -481,7 +474,7 @@ public class TestEvaluateXQuery {
}
@Test
- public void testMatchedEmptyStringAttribute() throws XPathFactoryConfigurationException, IOException {
+ public void testMatchedEmptyStringAttribute() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_ATTRIBUTE);
testRunner.setProperty("xquery.result.exist.2", "/*:fruitbasket/*[name='none']/color/text()");
@@ -496,7 +489,7 @@ public class TestEvaluateXQuery {
testRunner.getFlowFilesForRelationship(EvaluateXQuery.REL_NO_MATCH).get(0).assertContentEquals(XML_SNIPPET);
}
- @Test(expected = java.lang.AssertionError.class)
+ @Test
public void testMultipleXPathForContent() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_CONTENT);
@@ -504,11 +497,11 @@ public class TestEvaluateXQuery {
testRunner.setProperty("some.property.2", "/*:fruitbasket/fruit[2]");
testRunner.enqueue(XML_SNIPPET);
- testRunner.run();
+ assertThrows(AssertionError.class, testRunner::run);
}
@Test
- public void testWriteStringToAttribute() throws XPathFactoryConfigurationException, IOException {
+ public void testWriteStringToAttribute() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_ATTRIBUTE);
testRunner.setProperty("xquery.result2", "/*:fruitbasket/fruit[1]/name/text()");
@@ -523,7 +516,7 @@ public class TestEvaluateXQuery {
}
@Test
- public void testWriteStringToContent() throws XPathFactoryConfigurationException, IOException {
+ public void testWriteStringToContent() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_CONTENT);
testRunner.setProperty("some.property", "/*:fruitbasket/fruit[1]/name/text()");
@@ -533,13 +526,11 @@ public class TestEvaluateXQuery {
testRunner.assertAllFlowFilesTransferred(EvaluateXQuery.REL_MATCH, 1);
final MockFlowFile out = testRunner.getFlowFilesForRelationship(EvaluateXQuery.REL_MATCH).get(0);
- final byte[] outData = testRunner.getContentAsByteArray(out);
- final String outXml = new String(outData, "UTF-8");
- assertTrue(outXml.trim().equals("apple"));
+ out.assertContentEquals("apple");
}
@Test
- public void testWriteXmlToAttribute() throws XPathFactoryConfigurationException, IOException {
+ public void testWriteXmlToAttribute() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_ATTRIBUTE);
testRunner.setProperty("some.property", "/*:fruitbasket/fruit[1]/name");
@@ -555,7 +546,7 @@ public class TestEvaluateXQuery {
}
@Test
- public void testWriteXmlToContent() throws XPathFactoryConfigurationException, IOException {
+ public void testWriteXmlToContent() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_CONTENT);
testRunner.setProperty("some.property", "/*:fruitbasket/fruit[1]/name");
@@ -566,12 +557,12 @@ public class TestEvaluateXQuery {
testRunner.assertAllFlowFilesTransferred(EvaluateXQuery.REL_MATCH, 1);
final MockFlowFile out = testRunner.getFlowFilesForRelationship(EvaluateXQuery.REL_MATCH).get(0);
final byte[] outData = testRunner.getContentAsByteArray(out);
- final String outXml = new String(outData, "UTF-8");
+ final String outXml = new String(outData, StandardCharsets.UTF_8);
assertTrue(outXml.contains("<name xmlns:ns=\"http://namespace/1\">apple</name>"));
}
@Test
- public void testMatchesMultipleStringContent() throws XPathFactoryConfigurationException, IOException {
+ public void testMatchesMultipleStringContent() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_CONTENT);
testRunner.setProperty("some.property", "//fruit/name/text()");
@@ -585,14 +576,12 @@ public class TestEvaluateXQuery {
for (int i = 0; i < flowFilesForRelMatch.size(); i++) {
final MockFlowFile out = flowFilesForRelMatch.get(i);
- final byte[] outData = testRunner.getContentAsByteArray(out);
- final String outXml = new String(outData, "UTF-8");
- assertEquals(fruitNames[i], outXml.trim());
+ out.assertContentEquals(fruitNames[i]);
}
}
@Test
- public void testMatchesMultipleStringAttribute() throws XPathFactoryConfigurationException, IOException {
+ public void testMatchesMultipleStringAttribute() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_ATTRIBUTE);
testRunner.setProperty("some.property", "//fruit/name/text()");
@@ -605,14 +594,14 @@ public class TestEvaluateXQuery {
final MockFlowFile out = testRunner.getFlowFilesForRelationship(EvaluateXQuery.REL_MATCH).get(0);
for (int i = 0; i < fruitNames.length; i++) {
- final String outXml = out.getAttribute("some.property." + ((int) i + 1));
+ final String outXml = out.getAttribute("some.property." + (i + 1));
assertEquals(fruitNames[i], outXml.trim());
}
testRunner.getFlowFilesForRelationship(EvaluateXQuery.REL_MATCH).get(0).assertContentEquals(XML_SNIPPET);
}
@Test
- public void testMatchesMultipleXmlContent() throws XPathFactoryConfigurationException, IOException {
+ public void testMatchesMultipleXmlContent() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_CONTENT);
testRunner.setProperty("some.property", "//fruit/name");
@@ -627,14 +616,14 @@ public class TestEvaluateXQuery {
final MockFlowFile out = flowFilesForRelMatch.get(i);
final byte[] outData = testRunner.getContentAsByteArray(out);
- final String outXml = new String(outData, "UTF-8");
+ final String outXml = new String(outData, StandardCharsets.UTF_8);
String expectedXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><name xmlns:ns=\"http://namespace/1\">" + fruitNames[i] + "</name>";
assertEquals(expectedXml, outXml.trim());
}
}
@Test
- public void testMatchesMultipleXmlAttribute() throws XPathFactoryConfigurationException, IOException {
+ public void testMatchesMultipleXmlAttribute() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_ATTRIBUTE);
testRunner.setProperty("some.property", "//fruit/name");
@@ -647,7 +636,7 @@ public class TestEvaluateXQuery {
final MockFlowFile out = testRunner.getFlowFilesForRelationship(EvaluateXQuery.REL_MATCH).get(0);
for (int i = 0; i < fruitNames.length; i++) {
- final String outXml = out.getAttribute("some.property." + ((int) i + 1));
+ final String outXml = out.getAttribute("some.property." + (i + 1));
String expectedXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><name xmlns:ns=\"http://namespace/1\">" + fruitNames[i] + "</name>";
assertEquals(expectedXml, outXml.trim());
}
@@ -655,7 +644,7 @@ public class TestEvaluateXQuery {
}
@Test
- public void testSuccessForEmbeddedDocTypeValidation() throws XPathFactoryConfigurationException, IOException {
+ public void testSuccessForEmbeddedDocTypeValidation() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_CONTENT);
testRunner.setProperty(EvaluateXQuery.VALIDATE_DTD, "true");
@@ -666,13 +655,11 @@ public class TestEvaluateXQuery {
testRunner.assertAllFlowFilesTransferred(EvaluateXQuery.REL_MATCH, 1);
final MockFlowFile out = testRunner.getFlowFilesForRelationship(EvaluateXQuery.REL_MATCH).get(0);
- final byte[] outData = testRunner.getContentAsByteArray(out);
- final String outXml = new String(outData, "UTF-8");
- assertTrue(outXml.trim().equals("Hello"));
+ out.assertContentEquals("Hello");
}
@Test
- public void testSuccessForEmbeddedDocTypeValidationDisabled() throws XPathFactoryConfigurationException, IOException {
+ public void testFailureForEmbeddedDocTypeValidationDisabled() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_CONTENT);
testRunner.setProperty(EvaluateXQuery.VALIDATE_DTD, "false");
@@ -681,16 +668,12 @@ public class TestEvaluateXQuery {
testRunner.enqueue(XML_SNIPPET_EMBEDDED_DOCTYPE);
testRunner.run();
- testRunner.assertAllFlowFilesTransferred(EvaluateXQuery.REL_MATCH, 1);
- final MockFlowFile out = testRunner.getFlowFilesForRelationship(EvaluateXQuery.REL_MATCH).get(0);
- final byte[] outData = testRunner.getContentAsByteArray(out);
- final String outXml = new String(outData, "UTF-8");
- assertTrue(outXml.trim().equals("Hello"));
+ testRunner.assertAllFlowFilesTransferred(EvaluateXQuery.REL_FAILURE, 1);
}
@Test
- public void testFailureForExternalDocTypeWithDocTypeValidationEnabled() throws XPathFactoryConfigurationException, IOException {
+ public void testFailureForExternalDocTypeWithDocTypeValidationEnabled() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_CONTENT);
testRunner.setProperty("some.property", "/*:bundle/node/subNode[1]/value/text()");
@@ -701,9 +684,8 @@ public class TestEvaluateXQuery {
testRunner.assertAllFlowFilesTransferred(EvaluateXQuery.REL_FAILURE, 1);
}
-
@Test
- public void testSuccessForExternalDocTypeWithDocTypeValidationDisabled() throws XPathFactoryConfigurationException, IOException {
+ public void testFailureForExternalDocTypeWithDocTypeValidationDisabled() throws IOException {
final TestRunner testRunner = TestRunners.newTestRunner(new EvaluateXQuery());
testRunner.setProperty(EvaluateXQuery.DESTINATION, EvaluateXQuery.DESTINATION_CONTENT);
testRunner.setProperty(EvaluateXQuery.VALIDATE_DTD, "false");
@@ -712,10 +694,6 @@ public class TestEvaluateXQuery {
testRunner.enqueue(XML_SNIPPET_NONEXISTENT_DOCTYPE);
testRunner.run();
- testRunner.assertAllFlowFilesTransferred(EvaluateXQuery.REL_MATCH, 1);
- final MockFlowFile out = testRunner.getFlowFilesForRelationship(EvaluateXQuery.REL_MATCH).get(0);
- final byte[] outData = testRunner.getContentAsByteArray(out);
- final String outXml = new String(outData, "UTF-8");
- assertTrue(outXml.trim().equals("Hello"));
+ testRunner.assertAllFlowFilesTransferred(EvaluateXQuery.REL_FAILURE, 1);
}
}
diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/pom.xml b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/pom.xml
index c6d2c4d1c8..f496a6d431 100644
--- a/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/pom.xml
+++ b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/pom.xml
@@ -176,11 +176,6 @@
<version>${nifi.groovy.version}</version>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>org.apache.nifi</groupId>
- <artifactId>nifi-security-utils</artifactId>
- <version>1.16.1-SNAPSHOT</version>
- </dependency>
</dependencies>
<build>
<plugins>
diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/XMLFileLookupService.java b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/XMLFileLookupService.java
index ce9c37763d..aaeb8f21c9 100644
--- a/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/XMLFileLookupService.java
+++ b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/XMLFileLookupService.java
@@ -19,7 +19,7 @@ package org.apache.nifi.lookup;
import org.apache.nifi.annotation.documentation.CapabilityDescription;
import org.apache.nifi.annotation.documentation.Tags;
import org.apache.nifi.lookup.configuration2.CommonsConfigurationLookupService;
-import org.apache.nifi.security.xml.SafeXMLConfiguration;
+import org.apache.nifi.lookup.configuration2.SafeXMLConfiguration;
@Tags({"lookup", "cache", "enrich", "join", "xml", "reloadable", "key", "value"})
diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/configuration2/CommonsConfigurationLookupService.java b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/configuration2/CommonsConfigurationLookupService.java
index cbc17f4b62..6263a77cd0 100644
--- a/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/configuration2/CommonsConfigurationLookupService.java
+++ b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/configuration2/CommonsConfigurationLookupService.java
@@ -36,7 +36,6 @@ import org.apache.nifi.expression.ExpressionLanguageScope;
import org.apache.nifi.lookup.LookupFailureException;
import org.apache.nifi.lookup.StringLookupService;
import org.apache.nifi.reporting.InitializationException;
-import org.apache.nifi.security.xml.XXEValidator;
import java.io.File;
import java.lang.reflect.ParameterizedType;
diff --git a/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/xml/SafeXMLConfiguration.java b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/configuration2/SafeXMLConfiguration.java
similarity index 97%
rename from nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/xml/SafeXMLConfiguration.java
rename to nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/configuration2/SafeXMLConfiguration.java
index 44f29dcb40..5de11266b6 100644
--- a/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/xml/SafeXMLConfiguration.java
+++ b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/configuration2/SafeXMLConfiguration.java
@@ -14,11 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.nifi.security.xml;
+package org.apache.nifi.lookup.configuration2;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
+import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
@@ -45,7 +46,7 @@ public class SafeXMLConfiguration extends XMLConfiguration {
private static final String W3C_XML_SCHEMA =
"http://www.w3.org/2001/XMLSchema";
- // These features are used to disable processing external entities in the DocumentBuilderFactory to protect against XXE attacks
+ // These features are used to disable processing external entities to protect against XXE attacks
private static final String DISALLOW_DOCTYPES = "http://apache.org/xml/features/disallow-doctype-decl";
private static final String ALLOW_EXTERNAL_GENERAL_ENTITIES = "http://xml.org/sax/features/external-general-entities";
private static final String ALLOW_EXTERNAL_PARAM_ENTITIES = "http://xml.org/sax/features/external-parameter-entities";
@@ -90,6 +91,7 @@ public class SafeXMLConfiguration extends XMLConfiguration {
}
// Disable DTDs and external entities to protect against XXE
+ factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
factory.setAttribute(DISALLOW_DOCTYPES, true);
factory.setAttribute(ALLOW_EXTERNAL_GENERAL_ENTITIES, false);
factory.setAttribute(ALLOW_EXTERNAL_PARAM_ENTITIES, false);
diff --git a/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/xml/XXEValidator.java b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/configuration2/XXEValidator.java
similarity index 99%
rename from nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/xml/XXEValidator.java
rename to nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/configuration2/XXEValidator.java
index e9c54d5f41..087e7cb2ff 100644
--- a/nifi-commons/nifi-security-utils/src/main/java/org/apache/nifi/security/xml/XXEValidator.java
+++ b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/main/java/org/apache/nifi/lookup/configuration2/XXEValidator.java
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.nifi.security.xml;
+package org.apache.nifi.lookup.configuration2;
import java.io.BufferedReader;
import java.io.IOException;
diff --git a/nifi-commons/nifi-security-utils/src/test/java/org/apache/nifi/security/XXEValidatorTest.java b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/test/java/org/apache/nifi/lookup/configuration2/XXEValidatorTest.java
similarity index 98%
rename from nifi-commons/nifi-security-utils/src/test/java/org/apache/nifi/security/XXEValidatorTest.java
rename to nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/test/java/org/apache/nifi/lookup/configuration2/XXEValidatorTest.java
index fd2dceac38..a8aea1ce96 100644
--- a/nifi-commons/nifi-security-utils/src/test/java/org/apache/nifi/security/XXEValidatorTest.java
+++ b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/test/java/org/apache/nifi/lookup/configuration2/XXEValidatorTest.java
@@ -14,11 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.nifi.security;
+package org.apache.nifi.lookup.configuration2;
import org.apache.nifi.components.ValidationContext;
import org.apache.nifi.components.ValidationResult;
-import org.apache.nifi.security.xml.XXEValidator;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
diff --git a/nifi-commons/nifi-security-utils/src/test/resources/local_xxe_file.xml b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/test/resources/local_xxe_file.xml
similarity index 100%
rename from nifi-commons/nifi-security-utils/src/test/resources/local_xxe_file.xml
rename to nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/test/resources/local_xxe_file.xml
diff --git a/nifi-commons/nifi-security-utils/src/test/resources/multiline_xxe_file.xml b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/test/resources/multiline_xxe_file.xml
similarity index 100%
rename from nifi-commons/nifi-security-utils/src/test/resources/multiline_xxe_file.xml
rename to nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/test/resources/multiline_xxe_file.xml
diff --git a/nifi-commons/nifi-security-utils/src/test/resources/no_xxe.xml b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/test/resources/no_xxe.xml
similarity index 100%
rename from nifi-commons/nifi-security-utils/src/test/resources/no_xxe.xml
rename to nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/test/resources/no_xxe.xml
diff --git a/nifi-commons/nifi-security-utils/src/test/resources/remote_xxe_file.xml b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/test/resources/remote_xxe_file.xml
similarity index 100%
rename from nifi-commons/nifi-security-utils/src/test/resources/remote_xxe_file.xml
rename to nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/test/resources/remote_xxe_file.xml
diff --git a/nifi-commons/nifi-security-utils/src/test/resources/whitespace_xxe_file.xml b/nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/test/resources/whitespace_xxe_file.xml
similarity index 100%
rename from nifi-commons/nifi-security-utils/src/test/resources/whitespace_xxe_file.xml
rename to nifi-nar-bundles/nifi-standard-services/nifi-lookup-services-bundle/nifi-lookup-services/src/test/resources/whitespace_xxe_file.xml
diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/pom.xml b/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/pom.xml
index 19b8997874..d0b100a2a8 100755
--- a/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/pom.xml
+++ b/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/pom.xml
@@ -51,6 +51,11 @@
<artifactId>nifi-syslog-utils</artifactId>
<version>1.16.1-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>com.jayway.jsonpath</groupId>
<artifactId>json-path</artifactId>
diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/main/java/org/apache/nifi/windowsevent/WindowsEventLogRecordReader.java b/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/main/java/org/apache/nifi/windowsevent/WindowsEventLogRecordReader.java
index cf1e23e10a..c46299d11a 100644
--- a/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/main/java/org/apache/nifi/windowsevent/WindowsEventLogRecordReader.java
+++ b/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/main/java/org/apache/nifi/windowsevent/WindowsEventLogRecordReader.java
@@ -32,14 +32,17 @@ import org.apache.nifi.serialization.record.util.DataTypeUtils;
import org.apache.nifi.stream.io.NonCloseableInputStream;
import org.apache.nifi.util.StringUtils;
import org.apache.nifi.xml.inference.XmlSchemaInference;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.stream.StandardXMLEventReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLEventReaderProvider;
import javax.xml.stream.XMLEventReader;
-import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
+import javax.xml.transform.stream.StreamSource;
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -144,18 +147,13 @@ public class WindowsEventLogRecordReader implements RecordReader {
LAZY_TIMESTAMP_FORMAT = () -> tsf;
final FilterInputStream inputStream;
- final XMLInputFactory xmlInputFactory;
+ final XMLEventReaderProvider provider = new StandardXMLEventReaderProvider();
try {
- xmlInputFactory = XMLInputFactory.newInstance();
- // Avoid XXE Vulnerabilities
- xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
- xmlInputFactory.setProperty("javax.xml.stream.isSupportingExternalEntities", false);
-
inputStream = new NonCloseableInputStream(in);
inputStream.mark(Integer.MAX_VALUE);
- xmlEventReader = xmlInputFactory.createXMLEventReader(inputStream);
+ xmlEventReader = provider.getEventReader(new StreamSource(inputStream));
xmlSchemaInference = new XmlSchemaInference(new TimeValueInference(dateFormat, timeFormat, timestampFormat));
- } catch (XMLStreamException e) {
+ } catch (final ProcessingException e) {
throw new MalformedRecordException("Error creating XML Event reader from FlowFile input stream", e);
}
@@ -169,7 +167,7 @@ public class WindowsEventLogRecordReader implements RecordReader {
try {
// Restart the XML event stream and advance to the first Event tag
inputStream.reset();
- xmlEventReader = xmlInputFactory.createXMLEventReader(inputStream);
+ xmlEventReader = provider.getEventReader(new StreamSource(inputStream));
if (isArray) {
skipToNextStartTag();
}
diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/main/java/org/apache/nifi/xml/XMLRecordReader.java b/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/main/java/org/apache/nifi/xml/XMLRecordReader.java
index fd6d23b3e2..9de1a6253a 100644
--- a/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/main/java/org/apache/nifi/xml/XMLRecordReader.java
+++ b/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/main/java/org/apache/nifi/xml/XMLRecordReader.java
@@ -31,14 +31,16 @@ import org.apache.nifi.serialization.record.type.MapDataType;
import org.apache.nifi.serialization.record.type.RecordDataType;
import org.apache.nifi.serialization.record.util.DataTypeUtils;
import org.apache.nifi.util.StringUtils;
+import org.apache.nifi.xml.processing.stream.StandardXMLEventReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLEventReaderProvider;
import javax.xml.stream.XMLEventReader;
-import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
+import javax.xml.transform.stream.StreamSource;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
@@ -82,13 +84,8 @@ public class XMLRecordReader implements RecordReader {
LAZY_TIMESTAMP_FORMAT = () -> tsf;
try {
- final XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
-
- // Avoid XXE Vulnerabilities
- xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
- xmlInputFactory.setProperty("javax.xml.stream.isSupportingExternalEntities", false);
-
- xmlEventReader = xmlInputFactory.createXMLEventReader(in);
+ final XMLEventReaderProvider provider = new StandardXMLEventReaderProvider();
+ xmlEventReader = provider.getEventReader(new StreamSource(in));
if (isArray) {
skipNextStartTag();
diff --git a/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/main/java/org/apache/nifi/xml/inference/XmlRecordSource.java b/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/main/java/org/apache/nifi/xml/inference/XmlRecordSource.java
index 8352aed08d..f77a61422a 100644
--- a/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/main/java/org/apache/nifi/xml/inference/XmlRecordSource.java
+++ b/nifi-nar-bundles/nifi-standard-services/nifi-record-serialization-services-bundle/nifi-record-serialization-services/src/main/java/org/apache/nifi/xml/inference/XmlRecordSource.java
@@ -17,14 +17,17 @@
package org.apache.nifi.xml.inference;
import org.apache.nifi.schema.inference.RecordSource;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.stream.StandardXMLEventReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLEventReaderProvider;
import javax.xml.stream.XMLEventReader;
-import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
+import javax.xml.transform.stream.StreamSource;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
@@ -40,18 +43,13 @@ public class XmlRecordSource implements RecordSource<XmlNode> {
public XmlRecordSource(final InputStream in, final String contentFieldName, final boolean ignoreWrapper) throws IOException {
this.contentFieldName = contentFieldName;
try {
- final XMLInputFactory xmlInputFactory = XMLInputFactory.newInstance();
-
- // Avoid XXE Vulnerabilities
- xmlInputFactory.setProperty(XMLInputFactory.SUPPORT_DTD, false);
- xmlInputFactory.setProperty("javax.xml.stream.isSupportingExternalEntities", false);
-
- xmlEventReader = xmlInputFactory.createXMLEventReader(in);
+ final XMLEventReaderProvider provider = new StandardXMLEventReaderProvider();
+ xmlEventReader = provider.getEventReader(new StreamSource(in));
if (ignoreWrapper) {
readStartElement();
}
- } catch (XMLStreamException e) {
+ } catch (final ProcessingException|XMLStreamException e) {
throw new IOException("Could not parse XML", e);
}
}
diff --git a/nifi-nar-bundles/nifi-update-attribute-bundle/nifi-update-attribute-model/pom.xml b/nifi-nar-bundles/nifi-update-attribute-bundle/nifi-update-attribute-model/pom.xml
index 16cdda6a1c..3f0810fd43 100644
--- a/nifi-nar-bundles/nifi-update-attribute-bundle/nifi-update-attribute-model/pom.xml
+++ b/nifi-nar-bundles/nifi-update-attribute-bundle/nifi-update-attribute-model/pom.xml
@@ -26,7 +26,7 @@
<dependencies>
<dependency>
<groupId>org.apache.nifi</groupId>
- <artifactId>nifi-security-utils</artifactId>
+ <artifactId>nifi-xml-processing</artifactId>
<version>1.16.1-SNAPSHOT</version>
</dependency>
</dependencies>
diff --git a/nifi-nar-bundles/nifi-update-attribute-bundle/nifi-update-attribute-model/src/main/java/org/apache/nifi/update/attributes/serde/CriteriaSerDe.java b/nifi-nar-bundles/nifi-update-attribute-bundle/nifi-update-attribute-model/src/main/java/org/apache/nifi/update/attributes/serde/CriteriaSerDe.java
index 6ed0bed174..1d635e5fef 100644
--- a/nifi-nar-bundles/nifi-update-attribute-bundle/nifi-update-attribute-model/src/main/java/org/apache/nifi/update/attributes/serde/CriteriaSerDe.java
+++ b/nifi-nar-bundles/nifi-update-attribute-bundle/nifi-update-attribute-model/src/main/java/org/apache/nifi/update/attributes/serde/CriteriaSerDe.java
@@ -26,12 +26,15 @@ import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlRootElement;
-import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
-import org.apache.nifi.security.xml.XmlUtils;
+import javax.xml.transform.stream.StreamSource;
+
import org.apache.nifi.update.attributes.Criteria;
import org.apache.nifi.update.attributes.FlowFilePolicy;
import org.apache.nifi.update.attributes.Rule;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLStreamReaderProvider;
/**
*
@@ -121,13 +124,14 @@ public class CriteriaSerDe {
try {
// deserialize the binding
final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
- XMLStreamReader xsr = XmlUtils.createSafeReader(new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8)));
+ final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
+ XMLStreamReader xsr = provider.getStreamReader(new StreamSource(new ByteArrayInputStream(string.getBytes(StandardCharsets.UTF_8))));
final JAXBElement<CriteriaBinding> element = unmarshaller.unmarshal(xsr, CriteriaBinding.class);
// create the criteria from the binding
final CriteriaBinding binding = element.getValue();
criteria = new Criteria(binding.getFlowFilePolicy(), binding.getRules());
- } catch (final JAXBException | XMLStreamException e) {
+ } catch (final JAXBException | ProcessingException e) {
throw new IllegalArgumentException(e);
}
}
diff --git a/nifi-registry/nifi-registry-core/nifi-registry-framework/pom.xml b/nifi-registry/nifi-registry-core/nifi-registry-framework/pom.xml
index 4b7cbda76e..82e5108cfc 100644
--- a/nifi-registry/nifi-registry-core/nifi-registry-framework/pom.xml
+++ b/nifi-registry/nifi-registry-core/nifi-registry-framework/pom.xml
@@ -211,6 +211,11 @@
<artifactId>nifi-h2-database-migrator</artifactId>
<version>1.16.1-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
diff --git a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authentication/IdentityProviderFactory.java b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authentication/IdentityProviderFactory.java
index 3eddf9b028..8db74eb74b 100644
--- a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authentication/IdentityProviderFactory.java
+++ b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authentication/IdentityProviderFactory.java
@@ -27,7 +27,8 @@ import org.apache.nifi.registry.security.authentication.annotation.IdentityProvi
import org.apache.nifi.registry.security.authentication.generated.IdentityProviders;
import org.apache.nifi.registry.security.authentication.generated.Property;
import org.apache.nifi.registry.security.authentication.generated.Provider;
-import org.apache.nifi.registry.security.util.XmlUtils;
+import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLStreamReaderProvider;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
@@ -147,7 +148,8 @@ public class IdentityProviderFactory implements IdentityProviderLookup, Disposab
final Schema schema = schemaFactory.newSchema(IdentityProviders.class.getResource(LOGIN_IDENTITY_PROVIDERS_XSD));
// attempt to unmarshal
- XMLStreamReader xsr = XmlUtils.createSafeReader(new StreamSource(loginIdentityProvidersConfigurationFile));
+ final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
+ XMLStreamReader xsr = provider.getStreamReader(new StreamSource(loginIdentityProvidersConfigurationFile));
final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
unmarshaller.setSchema(schema);
final JAXBElement<IdentityProviders> element = unmarshaller.unmarshal(xsr, IdentityProviders.class);
diff --git a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AbstractPolicyBasedAuthorizer.java b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AbstractPolicyBasedAuthorizer.java
index 0509a3806f..16a6ec706a 100644
--- a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AbstractPolicyBasedAuthorizer.java
+++ b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AbstractPolicyBasedAuthorizer.java
@@ -20,15 +20,14 @@ import org.apache.nifi.registry.security.authorization.exception.AuthorizationAc
import org.apache.nifi.registry.security.authorization.exception.UninheritableAuthorizationsException;
import org.apache.nifi.registry.security.exception.SecurityProviderCreationException;
import org.apache.nifi.registry.security.exception.SecurityProviderDestructionException;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.parsers.DocumentProvider;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
@@ -47,7 +46,6 @@ import java.util.Set;
*/
public abstract class AbstractPolicyBasedAuthorizer implements ManagedAuthorizer {
- static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
static final XMLOutputFactory XML_OUTPUT_FACTORY = XMLOutputFactory.newInstance();
static final String USER_ELEMENT = "user";
@@ -378,8 +376,8 @@ public abstract class AbstractPolicyBasedAuthorizer implements ManagedAuthorizer
final byte[] fingerprintBytes = fingerprint.getBytes(StandardCharsets.UTF_8);
try (final ByteArrayInputStream in = new ByteArrayInputStream(fingerprintBytes)) {
- final DocumentBuilder docBuilder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
- final Document document = docBuilder.parse(in);
+ final DocumentProvider documentProvider = new StandardDocumentProvider();
+ final Document document = documentProvider.parse(in);
final Element rootElement = document.getDocumentElement();
// parse all the users and add them to the current authorizer
@@ -402,7 +400,7 @@ public abstract class AbstractPolicyBasedAuthorizer implements ManagedAuthorizer
Node policyNode = policyNodes.item(i);
accessPolicies.add(parsePolicy((Element) policyNode));
}
- } catch (SAXException | ParserConfigurationException | IOException e) {
+ } catch (final ProcessingException | IOException e) {
throw new AuthorizationAccessException("Unable to parse fingerprint", e);
}
diff --git a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AuthorizerFactory.java b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AuthorizerFactory.java
index 738f003573..90a3f0b5a8 100644
--- a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AuthorizerFactory.java
+++ b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/AuthorizerFactory.java
@@ -35,8 +35,10 @@ import org.apache.nifi.registry.security.exception.SecurityProviderCreationExcep
import org.apache.nifi.registry.security.exception.SecurityProviderDestructionException;
import org.apache.nifi.registry.security.identity.IdentityMapper;
import org.apache.nifi.registry.security.util.ClassLoaderUtils;
-import org.apache.nifi.registry.security.util.XmlUtils;
import org.apache.nifi.registry.service.RegistryService;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLStreamReaderProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
@@ -45,7 +47,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.Nullable;
import org.springframework.transaction.annotation.Transactional;
-import org.xml.sax.SAXException;
import javax.sql.DataSource;
import javax.xml.XMLConstants;
@@ -53,7 +54,7 @@ import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
-import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
@@ -300,9 +301,11 @@ public class AuthorizerFactory implements UserGroupProviderLookup, AccessPolicyP
// attempt to unmarshal
final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
unmarshaller.setSchema(schema);
- final JAXBElement<Authorizers> element = unmarshaller.unmarshal(XmlUtils.createSafeReader(new StreamSource(authorizersConfigurationFile)), Authorizers.class);
+ final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
+ final XMLStreamReader reader = provider.getStreamReader(new StreamSource(authorizersConfigurationFile));
+ final JAXBElement<Authorizers> element = unmarshaller.unmarshal(reader, Authorizers.class);
return element.getValue();
- } catch (XMLStreamException | SAXException | JAXBException e) {
+ } catch (final ProcessingException | JAXBException e) {
throw new Exception("Unable to load the authorizer configuration file at: " + authorizersConfigurationFile.getAbsolutePath(), e);
}
} else {
diff --git a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/StandardManagedAuthorizer.java b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/StandardManagedAuthorizer.java
index 58bcf55464..db2f7d28dd 100644
--- a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/StandardManagedAuthorizer.java
+++ b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/StandardManagedAuthorizer.java
@@ -22,15 +22,14 @@ import org.apache.nifi.registry.security.authorization.exception.UninheritableAu
import org.apache.nifi.registry.security.exception.SecurityProviderCreationException;
import org.apache.nifi.registry.security.exception.SecurityProviderDestructionException;
import org.apache.nifi.registry.util.PropertyValue;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.parsers.DocumentProvider;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
@@ -42,7 +41,6 @@ import java.util.Set;
public class StandardManagedAuthorizer implements ManagedAuthorizer {
- private static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
private static final XMLOutputFactory XML_OUTPUT_FACTORY = XMLOutputFactory.newInstance();
private static final String USER_GROUP_PROVIDER_ELEMENT = "userGroupProvider";
@@ -212,8 +210,8 @@ public class StandardManagedAuthorizer implements ManagedAuthorizer {
final byte[] fingerprintBytes = fingerprint.getBytes(StandardCharsets.UTF_8);
try (final ByteArrayInputStream in = new ByteArrayInputStream(fingerprintBytes)) {
- final DocumentBuilder docBuilder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
- final Document document = docBuilder.parse(in);
+ final DocumentProvider documentProvider = new StandardDocumentProvider();
+ final Document document = documentProvider.parse(in);
final Element rootElement = document.getDocumentElement();
final NodeList accessPolicyProviderList = rootElement.getElementsByTagName(ACCESS_POLICY_PROVIDER_ELEMENT);
@@ -229,7 +227,7 @@ public class StandardManagedAuthorizer implements ManagedAuthorizer {
final Node accessPolicyProvider = accessPolicyProviderList.item(0);
final Node userGroupProvider = userGroupProviderList.item(0);
return new FingerprintHolder(accessPolicyProvider.getTextContent(), userGroupProvider.getTextContent());
- } catch (SAXException | ParserConfigurationException | IOException e) {
+ } catch (final ProcessingException | IOException e) {
throw new AuthorizationAccessException("Unable to parse fingerprint", e);
}
}
diff --git a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/file/FileAccessPolicyProvider.java b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/file/FileAccessPolicyProvider.java
index 31e77a1835..3de86089a8 100644
--- a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/file/FileAccessPolicyProvider.java
+++ b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/file/FileAccessPolicyProvider.java
@@ -37,6 +37,9 @@ import org.apache.nifi.registry.security.exception.SecurityProviderCreationExcep
import org.apache.nifi.registry.security.exception.SecurityProviderDestructionException;
import org.apache.nifi.registry.security.identity.IdentityMapper;
import org.apache.nifi.registry.util.PropertyValue;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.parsers.DocumentProvider;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
@@ -51,9 +54,6 @@ import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
@@ -95,7 +95,6 @@ public class FileAccessPolicyProvider extends AbstractConfigurableAccessPolicyPr
}
}
- private static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
private static final XMLOutputFactory XML_OUTPUT_FACTORY = XMLOutputFactory.newInstance();
private static final String POLICY_ELEMENT = "policy";
@@ -336,8 +335,8 @@ public class FileAccessPolicyProvider extends AbstractConfigurableAccessPolicyPr
final byte[] fingerprintBytes = fingerprint.getBytes(StandardCharsets.UTF_8);
try (final ByteArrayInputStream in = new ByteArrayInputStream(fingerprintBytes)) {
- final DocumentBuilder docBuilder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
- final Document document = docBuilder.parse(in);
+ final DocumentProvider documentProvider = new StandardDocumentProvider();
+ final Document document = documentProvider.parse(in);
final Element rootElement = document.getDocumentElement();
// parse all the policies and add them to the current access policy provider
@@ -346,7 +345,7 @@ public class FileAccessPolicyProvider extends AbstractConfigurableAccessPolicyPr
Node policyNode = policyNodes.item(i);
policies.add(parsePolicy((Element) policyNode));
}
- } catch (SAXException | ParserConfigurationException | IOException e) {
+ } catch (final ProcessingException | IOException e) {
throw new AuthorizationAccessException("Unable to parse fingerprint", e);
}
diff --git a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/file/FileUserGroupProvider.java b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/file/FileUserGroupProvider.java
index ba7ca9c5fb..c1679cf28a 100644
--- a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/file/FileUserGroupProvider.java
+++ b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/authorization/file/FileUserGroupProvider.java
@@ -34,6 +34,9 @@ import org.apache.nifi.registry.security.exception.SecurityProviderCreationExcep
import org.apache.nifi.registry.security.exception.SecurityProviderDestructionException;
import org.apache.nifi.registry.security.identity.IdentityMapper;
import org.apache.nifi.registry.util.PropertyValue;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.parsers.DocumentProvider;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
@@ -48,9 +51,6 @@ import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
@@ -92,7 +92,6 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
}
}
- private static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
private static final XMLOutputFactory XML_OUTPUT_FACTORY = XMLOutputFactory.newInstance();
private static final String USER_ELEMENT = "user";
@@ -482,8 +481,8 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
final byte[] fingerprintBytes = fingerprint.getBytes(StandardCharsets.UTF_8);
try (final ByteArrayInputStream in = new ByteArrayInputStream(fingerprintBytes)) {
- final DocumentBuilder docBuilder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
- final Document document = docBuilder.parse(in);
+ final DocumentProvider documentProvider = new StandardDocumentProvider();
+ final Document document = documentProvider.parse(in);
final Element rootElement = document.getDocumentElement();
// parse all the users and add them to the current user group provider
@@ -499,7 +498,7 @@ public class FileUserGroupProvider implements ConfigurableUserGroupProvider {
Node groupNode = groupNodes.item(i);
groups.add(parseGroup((Element) groupNode));
}
- } catch (SAXException | ParserConfigurationException | IOException e) {
+ } catch (final ProcessingException | IOException e) {
throw new AuthorizationAccessException("Unable to parse fingerprint", e);
}
diff --git a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/util/XmlUtils.java b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/util/XmlUtils.java
deleted file mode 100644
index 2caa8faa46..0000000000
--- a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/security/util/XmlUtils.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.nifi.registry.security.util;
-
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamReader;
-import javax.xml.transform.stream.StreamSource;
-import java.io.InputStream;
-
-public class XmlUtils {
-
- public static XMLStreamReader createSafeReader(InputStream inputStream) throws XMLStreamException {
- if (inputStream == null) {
- throw new IllegalArgumentException("The provided input stream cannot be null");
- }
- return createSafeReader(new StreamSource(inputStream));
- }
-
- public static XMLStreamReader createSafeReader(StreamSource source) throws XMLStreamException {
- if (source == null) {
- throw new IllegalArgumentException("The provided source cannot be null");
- }
-
- XMLInputFactory xif = XMLInputFactory.newFactory();
- xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
- xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
- return xif.createXMLStreamReader(source);
- }
-}
diff --git a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/alias/RegistryUrlAliasService.java b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/alias/RegistryUrlAliasService.java
index b9e6e74711..650fb01366 100644
--- a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/alias/RegistryUrlAliasService.java
+++ b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/main/java/org/apache/nifi/registry/service/alias/RegistryUrlAliasService.java
@@ -21,9 +21,11 @@ import org.apache.nifi.flow.VersionedProcessGroup;
import org.apache.nifi.registry.properties.NiFiRegistryProperties;
import org.apache.nifi.registry.provider.ProviderFactoryException;
import org.apache.nifi.registry.provider.StandardProviderFactory;
-import org.apache.nifi.registry.security.util.XmlUtils;
import org.apache.nifi.registry.url.aliaser.generated.Alias;
import org.apache.nifi.registry.url.aliaser.generated.Aliases;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.stream.StandardXMLStreamReaderProvider;
+import org.apache.nifi.xml.processing.stream.XMLStreamReaderProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.xml.sax.SAXException;
@@ -33,7 +35,7 @@ import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
-import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
@@ -84,9 +86,11 @@ public class RegistryUrlAliasService {
final Unmarshaller unmarshaller = JAXB_CONTEXT.createUnmarshaller();
unmarshaller.setSchema(schema);
- final JAXBElement<Aliases> element = unmarshaller.unmarshal(XmlUtils.createSafeReader(new StreamSource(configurationFile)), Aliases.class);
+ final XMLStreamReaderProvider provider = new StandardXMLStreamReaderProvider();
+ final XMLStreamReader reader = provider.getStreamReader(new StreamSource(configurationFile));
+ final JAXBElement<Aliases> element = unmarshaller.unmarshal(reader, Aliases.class);
return element.getValue().getAlias();
- } catch (SAXException | JAXBException | XMLStreamException e) {
+ } catch (final SAXException | JAXBException | ProcessingException e) {
throw new ProviderFactoryException("Unable to load the registry alias configuration file at: " + configurationFile.getAbsolutePath(), e);
}
} else {
diff --git a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/test/java/org/apache/nifi/registry/service/extension/docs/XmlValidator.java b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/test/java/org/apache/nifi/registry/service/extension/docs/XmlValidator.java
index 41cb6578f5..dfcaac1800 100644
--- a/nifi-registry/nifi-registry-core/nifi-registry-framework/src/test/java/org/apache/nifi/registry/service/extension/docs/XmlValidator.java
+++ b/nifi-registry/nifi-registry-core/nifi-registry-framework/src/test/java/org/apache/nifi/registry/service/extension/docs/XmlValidator.java
@@ -16,23 +16,25 @@
*/
package org.apache.nifi.registry.service.extension.docs;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.parsers.DocumentProvider;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.junit.Assert;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-import java.io.IOException;
-import java.io.StringReader;
+import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
public class XmlValidator {
+ private static final String DOCTYPE = "<!DOCTYPE html>";
+
+ private static final String EMPTY = "";
public static void assertXmlValid(String xml) {
+ final String html = xml.replace(DOCTYPE, EMPTY);
try {
- final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
- dbf.setNamespaceAware(true);
- dbf.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
- } catch (SAXException | IOException | ParserConfigurationException e) {
+ final DocumentProvider provider = new StandardDocumentProvider();
+ provider.parse(new ByteArrayInputStream(html.getBytes(StandardCharsets.UTF_8)));
+ } catch (final ProcessingException e) {
Assert.fail(e.getMessage());
}
}
@@ -40,8 +42,4 @@ public class XmlValidator {
public static void assertContains(String original, String subword) {
Assert.assertTrue(original + " did not contain: " + subword, original.contains(subword));
}
-
- public static void assertNotContains(String original, String subword) {
- Assert.assertFalse(original + " did contain: " + subword, original.contains(subword));
- }
}
diff --git a/nifi-registry/nifi-registry-extensions/nifi-registry-ranger/nifi-registry-ranger-plugin/pom.xml b/nifi-registry/nifi-registry-extensions/nifi-registry-ranger/nifi-registry-ranger-plugin/pom.xml
index 4b8f1b55e7..b24a23c40f 100644
--- a/nifi-registry/nifi-registry-extensions/nifi-registry-ranger/nifi-registry-ranger-plugin/pom.xml
+++ b/nifi-registry/nifi-registry-extensions/nifi-registry-ranger/nifi-registry-ranger-plugin/pom.xml
@@ -55,6 +55,13 @@
<!-- The one in registry/lib can be used -->
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ <!-- The one in registry/lib can be used -->
+ <scope>provided</scope>
+ </dependency>
<dependency>
<groupId>org.apache.nifi.registry</groupId>
<artifactId>nifi-registry-ranger-jersey-bundle</artifactId>
diff --git a/nifi-registry/nifi-registry-extensions/nifi-registry-ranger/nifi-registry-ranger-plugin/src/main/java/org/apache/nifi/registry/ranger/RangerAuthorizer.java b/nifi-registry/nifi-registry-extensions/nifi-registry-ranger/nifi-registry-ranger-plugin/src/main/java/org/apache/nifi/registry/ranger/RangerAuthorizer.java
index 6fa6fe2e4f..134b792e70 100644
--- a/nifi-registry/nifi-registry-extensions/nifi-registry-ranger/nifi-registry-ranger-plugin/src/main/java/org/apache/nifi/registry/ranger/RangerAuthorizer.java
+++ b/nifi-registry/nifi-registry-extensions/nifi-registry-ranger/nifi-registry-ranger-plugin/src/main/java/org/apache/nifi/registry/ranger/RangerAuthorizer.java
@@ -39,6 +39,9 @@ import org.apache.nifi.registry.security.authorization.exception.AuthorizationAc
import org.apache.nifi.registry.security.authorization.exception.UninheritableAuthorizationsException;
import org.apache.nifi.registry.security.exception.SecurityProviderCreationException;
import org.apache.nifi.registry.util.PropertyValue;
+import org.apache.nifi.xml.processing.ProcessingException;
+import org.apache.nifi.xml.processing.parsers.DocumentProvider;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.apache.ranger.audit.model.AuthzAuditEvent;
import org.apache.ranger.authorization.hadoop.config.RangerConfiguration;
import org.apache.ranger.authorization.hadoop.config.RangerPluginConfig;
@@ -52,11 +55,7 @@ import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
@@ -80,8 +79,6 @@ public class RangerAuthorizer implements ManagedAuthorizer, AuthorizationAuditor
private static final Logger logger = LoggerFactory.getLogger(RangerAuthorizer.class);
- private static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
-
private static final String USER_GROUP_PROVIDER_ELEMENT = "userGroupProvider";
static final String USER_GROUP_PROVIDER = "User Group Provider";
@@ -326,8 +323,8 @@ public class RangerAuthorizer implements ManagedAuthorizer, AuthorizationAuditor
final StringWriter out = new StringWriter();
try {
// create the document
- final DocumentBuilder documentBuilder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
- final Document document = documentBuilder.newDocument();
+ final DocumentProvider documentProvider = new StandardDocumentProvider();
+ final Document document = documentProvider.newDocument();
// create the root element
final Element managedRangerAuthorizationsElement = document.createElement("managedRangerAuthorizations");
@@ -344,7 +341,7 @@ public class RangerAuthorizer implements ManagedAuthorizer, AuthorizationAuditor
final Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.transform(new DOMSource(document), new StreamResult(out));
- } catch (ParserConfigurationException | TransformerException e) {
+ } catch (final ProcessingException | TransformerException e) {
throw new AuthorizationAccessException("Unable to generate fingerprint", e);
}
@@ -355,8 +352,8 @@ public class RangerAuthorizer implements ManagedAuthorizer, AuthorizationAuditor
final byte[] fingerprintBytes = fingerprint.getBytes(StandardCharsets.UTF_8);
try (final ByteArrayInputStream in = new ByteArrayInputStream(fingerprintBytes)) {
- final DocumentBuilder docBuilder = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
- final Document document = docBuilder.parse(in);
+ final DocumentProvider documentProvider = new StandardDocumentProvider();
+ final Document document = documentProvider.parse(in);
final Element rootElement = document.getDocumentElement();
final NodeList userGroupProviderList = rootElement.getElementsByTagName(USER_GROUP_PROVIDER_ELEMENT);
@@ -366,7 +363,7 @@ public class RangerAuthorizer implements ManagedAuthorizer, AuthorizationAuditor
final Node userGroupProvider = userGroupProviderList.item(0);
return userGroupProvider.getTextContent();
- } catch (SAXException | ParserConfigurationException | IOException e) {
+ } catch (final ProcessingException | IOException e) {
throw new AuthorizationAccessException("Unable to parse fingerprint", e);
}
}
diff --git a/nifi-system-tests/nifi-system-test-suite/pom.xml b/nifi-system-tests/nifi-system-test-suite/pom.xml
index a485380c60..a0863e107d 100644
--- a/nifi-system-tests/nifi-system-test-suite/pom.xml
+++ b/nifi-system-tests/nifi-system-test-suite/pom.xml
@@ -166,6 +166,16 @@
<artifactId>nifi-bootstrap</artifactId>
<version>1.16.1-SNAPSHOT</version>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-security-utils</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ </dependency>
<dependency>
<groupId>org.apache.nifi</groupId>
<artifactId>nifi-jetty-bundle</artifactId>
diff --git a/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/clustering/JoinClusterWithDifferentFlow.java b/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/clustering/JoinClusterWithDifferentFlow.java
index c53bd0b3d9..d5c9a8a15f 100644
--- a/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/clustering/JoinClusterWithDifferentFlow.java
+++ b/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/clustering/JoinClusterWithDifferentFlow.java
@@ -20,7 +20,6 @@ import org.apache.nifi.controller.serialization.FlowEncodingVersion;
import org.apache.nifi.controller.serialization.FlowFromDOMFactory;
import org.apache.nifi.encrypt.PropertyEncryptor;
import org.apache.nifi.encrypt.PropertyEncryptorFactory;
-import org.apache.nifi.security.xml.XmlUtils;
import org.apache.nifi.tests.system.InstanceConfiguration;
import org.apache.nifi.tests.system.NiFiInstance;
import org.apache.nifi.tests.system.NiFiInstanceFactory;
@@ -45,20 +44,19 @@ import org.apache.nifi.web.api.entity.ControllerServicesEntity;
import org.apache.nifi.web.api.entity.NodeEntity;
import org.apache.nifi.web.api.entity.ParameterEntity;
import org.apache.nifi.web.api.entity.ProcessorEntity;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.junit.jupiter.api.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
-import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
-import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.ParserConfigurationException;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
@@ -142,8 +140,8 @@ public class JoinClusterWithDifferentFlow extends NiFiSystemIT {
final File confDir = backupFile.getParentFile();
final String loadedFlow = readFlow(new File(confDir, "flow.xml.gz"));
- final DocumentBuilder documentBuilder = XmlUtils.createSafeDocumentBuilder(false);
- final Document document = documentBuilder.parse(new InputSource(new StringReader(loadedFlow)));
+ final StandardDocumentProvider documentProvider = new StandardDocumentProvider();
+ final Document document = documentProvider.parse(new ByteArrayInputStream(loadedFlow.getBytes(StandardCharsets.UTF_8)));
final Element rootElement = (Element) document.getElementsByTagName("flowController").item(0);
final FlowEncodingVersion encodingVersion = FlowEncodingVersion.parse(rootElement);
diff --git a/nifi-toolkit/nifi-toolkit-flowanalyzer/pom.xml b/nifi-toolkit/nifi-toolkit-flowanalyzer/pom.xml
index 7f7f1f47a8..179fa42dbe 100644
--- a/nifi-toolkit/nifi-toolkit-flowanalyzer/pom.xml
+++ b/nifi-toolkit/nifi-toolkit-flowanalyzer/pom.xml
@@ -24,6 +24,11 @@
<version>1.16.1-SNAPSHOT</version>
<scope>compile</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.nifi</groupId>
+ <artifactId>nifi-xml-processing</artifactId>
+ <version>1.17.0-SNAPSHOT</version>
+ </dependency>
</dependencies>
<parent>
diff --git a/nifi-toolkit/nifi-toolkit-flowanalyzer/src/main/java/org/apache/nifi/toolkit/flowanalyzer/FlowAnalyzerDriver.java b/nifi-toolkit/nifi-toolkit-flowanalyzer/src/main/java/org/apache/nifi/toolkit/flowanalyzer/FlowAnalyzerDriver.java
index 3b9a8463ac..6b5e23802f 100644
--- a/nifi-toolkit/nifi-toolkit-flowanalyzer/src/main/java/org/apache/nifi/toolkit/flowanalyzer/FlowAnalyzerDriver.java
+++ b/nifi-toolkit/nifi-toolkit-flowanalyzer/src/main/java/org/apache/nifi/toolkit/flowanalyzer/FlowAnalyzerDriver.java
@@ -21,8 +21,8 @@ import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.zip.GZIPInputStream;
-import javax.xml.parsers.DocumentBuilder;
-import org.apache.nifi.security.xml.XmlUtils;
+import org.apache.nifi.xml.processing.parsers.DocumentProvider;
+import org.apache.nifi.xml.processing.parsers.StandardDocumentProvider;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
@@ -71,8 +71,8 @@ public class FlowAnalyzerDriver {
System.out.println("Using flow=" + input);
try {
- DocumentBuilder documentBuilder = XmlUtils.createSafeDocumentBuilder(false);
- Document document = documentBuilder.parse(gzipStream);
+ final DocumentProvider documentProvider = new StandardDocumentProvider();
+ Document document = documentProvider.parse(gzipStream);
NodeList connectionNode = document.getElementsByTagName(CONST_XMLNODE_CONNECTION);
for (int x = 0; x < connectionNode.getLength(); x++) {