This is an automated email from the ASF dual-hosted git repository.
pvillard pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git
The following commit(s) were added to refs/heads/main by this push:
new 8011bf482c3 NIFI-5779 Applied Secure Processing in TransformXml to
Sources
8011bf482c3 is described below
commit 8011bf482c3eaef56e9bfe78efadce37cc019c81
Author: exceptionfactory <[email protected]>
AuthorDate: Tue Mar 3 22:17:03 2026 -0600
NIFI-5779 Applied Secure Processing in TransformXml to Sources
This closes #10959.
Signed-off-by: Pierre Villard <[email protected]>
---
.../nifi/processors/standard/TransformXml.java | 34 +++++++++++++++++-----
.../nifi/processors/standard/TestTransformXml.java | 17 +++++++++--
2 files changed, 41 insertions(+), 10 deletions(-)
diff --git
a/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/TransformXml.java
b/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/TransformXml.java
index 55e50a395fd..13e6e317d5b 100644
---
a/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/TransformXml.java
+++
b/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/main/java/org/apache/nifi/processors/standard/TransformXml.java
@@ -184,8 +184,12 @@ public class TransformXml extends AbstractProcessor {
REL_FAILURE
);
+ private static final XMLStreamReaderProvider STREAM_READER_PROVIDER = new
StandardXMLStreamReaderProvider();
+
private LoadingCache<String, Templates> cache;
+ private volatile boolean secureProcessingEnabled;
+
@Override
public Set<Relationship> getRelationships() {
return RELATIONSHIPS;
@@ -250,6 +254,8 @@ public class TransformXml extends AbstractProcessor {
@OnScheduled
public void onScheduled(final ProcessContext context) {
+ secureProcessingEnabled =
context.getProperty(SECURE_PROCESSING).asBoolean();
+
final ComponentLog logger = getLogger();
final Integer cacheSize = context.getProperty(CACHE_SIZE).asInteger();
final Long cacheTTL =
context.getProperty(CACHE_TTL_AFTER_LAST_ACCESS).asTimePeriod(TimeUnit.SECONDS);
@@ -302,7 +308,7 @@ public class TransformXml extends AbstractProcessor {
}
}
- final Source source = new
StreamSource(bufferedInputStream);
+ final Source source = getSource(bufferedInputStream);
final Result result = new StreamResult(outputStream);
transformer.transform(source, result);
} catch (final Exception e) {
@@ -335,18 +341,17 @@ public class TransformXml extends AbstractProcessor {
@SuppressWarnings("unchecked")
private Templates newTemplates(final ProcessContext context, final String
path) throws TransformerConfigurationException, LookupFailureException {
- final boolean secureProcessing =
context.getProperty(SECURE_PROCESSING).asBoolean();
- final TransformerFactory transformerFactory =
getTransformerFactory(secureProcessing);
+ final TransformerFactory transformerFactory = getTransformerFactory();
final LookupService<String> lookupService =
context.getProperty(XSLT_CONTROLLER).asControllerService(LookupService.class);
final boolean filePath = context.getProperty(XSLT_FILE_NAME).isSet();
final StreamSource templateSource = getTemplateSource(lookupService,
path, filePath);
- final Source configuredTemplateSource = secureProcessing ?
getSecureSource(templateSource) : templateSource;
+ final Source configuredTemplateSource = secureProcessingEnabled ?
getSecureSource(templateSource) : templateSource;
return transformerFactory.newTemplates(configuredTemplateSource);
}
- private TransformerFactory getTransformerFactory(final boolean
secureProcessing) throws TransformerConfigurationException {
+ private TransformerFactory getTransformerFactory() throws
TransformerConfigurationException {
final TransformerFactory factory = TransformerFactory.newInstance();
- if (secureProcessing) {
+ if (secureProcessingEnabled) {
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
factory.setFeature("http://saxon.sf.net/feature/parserFeature?uri=http://xml.org/sax/features/external-parameter-entities",
false);
factory.setFeature("http://saxon.sf.net/feature/parserFeature?uri=http://xml.org/sax/features/external-general-entities",
false);
@@ -375,10 +380,23 @@ public class TransformXml extends AbstractProcessor {
return streamSource;
}
+ private Source getSource(final InputStream inputStream) {
+ final Source source;
+
+ final StreamSource streamSource = new StreamSource(inputStream);
+ if (secureProcessingEnabled) {
+ final XMLStreamReader streamReader =
STREAM_READER_PROVIDER.getStreamReader(streamSource);
+ source = new StAXSource(streamReader);
+ } else {
+ source = streamSource;
+ }
+
+ return source;
+ }
+
private Source getSecureSource(final StreamSource streamSource) throws
TransformerConfigurationException {
- final XMLStreamReaderProvider provider = new
StandardXMLStreamReaderProvider();
try {
- final XMLStreamReader streamReader =
provider.getStreamReader(streamSource);
+ final XMLStreamReader streamReader =
STREAM_READER_PROVIDER.getStreamReader(streamSource);
return new StAXSource(streamReader);
} catch (final ProcessingException e) {
throw new TransformerConfigurationException("XSLT Source Stream
Reader creation failed", e);
diff --git
a/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestTransformXml.java
b/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestTransformXml.java
index f6fae788a4b..4807d63bb8d 100644
---
a/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestTransformXml.java
+++
b/nifi-extension-bundles/nifi-standard-bundle/nifi-standard-processors/src/test/java/org/apache/nifi/processors/standard/TestTransformXml.java
@@ -263,11 +263,12 @@ public class TestTransformXml {
}
@Test
- public void testTransformSecureProcessingEnabledXmlWithEntity() {
+ public void
testTransformSecureProcessingEnabledXmlWithDocumentTypeDefinition() {
runner.setProperty(TransformXml.XSLT_FILE_NAME,
"src/test/resources/TestTransformXml/doc-node.xsl");
runner.setProperty(TransformXml.INDENT_OUTPUT,
Boolean.FALSE.toString());
+ runner.setProperty(TransformXml.SECURE_PROCESSING,
Boolean.TRUE.toString());
- final String input = "<!DOCTYPE doc [<!ENTITY uri SYSTEM
\"http://127.0.0.1\" >]><doc>&uri;</doc>";
+ final String input = "<!DOCTYPE doc SYSTEM \"doc.dtd\"><doc></doc>";
runner.enqueue(input);
runner.run();
@@ -278,6 +279,18 @@ public class TestTransformXml {
transformed.assertContentEquals(expected);
}
+ @Test
+ public void testTransformSecureProcessingEnabledXmlWithEntity() {
+ runner.setProperty(TransformXml.XSLT_FILE_NAME,
"src/test/resources/TestTransformXml/doc-node.xsl");
+ runner.setProperty(TransformXml.INDENT_OUTPUT,
Boolean.FALSE.toString());
+
+ final String input = "<!DOCTYPE doc [<!ENTITY uri SYSTEM
\"http://127.0.0.1\" >]><doc>&uri;</doc>";
+ runner.enqueue(input);
+ runner.run();
+
+ runner.assertAllFlowFilesTransferred(TransformXml.REL_FAILURE);
+ }
+
@Test
public void testTransformSecureProcessingEnabledXslWithEntity() throws
IOException {
runner.setProperty(TransformXml.XSLT_FILE_NAME,
"src/test/resources/TestTransformXml/doctype-entity-file-uri.xsl");