From b042eb01e8ac1a23e2f5d4c9eee5b68ffe854e48 Mon Sep 17 00:00:00 2001
From: exceptionfactory
Date: Tue, 30 May 2023 13:05:07 -0500
Subject: [PATCH] NIFI-11614 Improved Validation for
JndiJmsConnectionFactoryProvider
This closes #7313.
Signed-off-by: Peter Turcsanyi
---
.../JndiJmsConnectionFactoryProperties.java | 90 +++++++++++++-
.../additionalDetails.html | 54 +++++++-
.../JndiJmsConnectionFactoryProviderTest.java | 116 ++++++++++++++++++
3 files changed, 255 insertions(+), 5 deletions(-)
create mode 100644 nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/test/java/org/apache/nifi/jms/cf/JndiJmsConnectionFactoryProviderTest.java
diff --git a/nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/main/java/org/apache/nifi/jms/cf/JndiJmsConnectionFactoryProperties.java b/nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/main/java/org/apache/nifi/jms/cf/JndiJmsConnectionFactoryProperties.java
index 93d98341f3..823ae0d976 100644
--- a/nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/main/java/org/apache/nifi/jms/cf/JndiJmsConnectionFactoryProperties.java
+++ b/nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/main/java/org/apache/nifi/jms/cf/JndiJmsConnectionFactoryProperties.java
@@ -18,6 +18,8 @@ package org.apache.nifi.jms.cf;
import org.apache.nifi.components.PropertyDescriptor;
import org.apache.nifi.components.PropertyDescriptor.Builder;
+import org.apache.nifi.components.ValidationContext;
+import org.apache.nifi.components.ValidationResult;
import org.apache.nifi.components.Validator;
import org.apache.nifi.components.resource.ResourceCardinality;
import org.apache.nifi.components.resource.ResourceType;
@@ -25,12 +27,20 @@ import org.apache.nifi.expression.ExpressionLanguageScope;
import org.apache.nifi.processor.util.StandardValidators;
import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
import java.util.List;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
import static org.apache.nifi.processor.util.StandardValidators.NON_EMPTY_VALIDATOR;
public class JndiJmsConnectionFactoryProperties {
+ public static final String URL_SCHEMES_ALLOWED_PROPERTY = "org.apache.nifi.jms.cf.jndi.provider.url.schemes.allowed";
+
public static final PropertyDescriptor JNDI_INITIAL_CONTEXT_FACTORY = new Builder()
.name("java.naming.factory.initial")
.displayName("JNDI Initial Context Factory Class")
@@ -43,9 +53,9 @@ public class JndiJmsConnectionFactoryProperties {
public static final PropertyDescriptor JNDI_PROVIDER_URL = new Builder()
.name("java.naming.provider.url")
.displayName("JNDI Provider URL")
- .description("The URL of the JNDI Provider to use (java.naming.provider.url).")
+ .description("The URL of the JNDI Provider to use as the value for java.naming.provider.url. See additional details documentation for allowed URL schemes.")
.required(true)
- .addValidator(NON_EMPTY_VALIDATOR)
+ .addValidator(new JndiJmsProviderUrlValidator())
.expressionLanguageSupported(ExpressionLanguageScope.VARIABLE_REGISTRY)
.build();
@@ -114,4 +124,80 @@ public class JndiJmsConnectionFactoryProperties {
.build();
}
+ static class JndiJmsProviderUrlValidator implements Validator {
+
+ private static final Pattern URL_SCHEME_PATTERN = Pattern.compile("^([^:]+)://.+$");
+
+ private static final int SCHEME_GROUP = 1;
+
+ private static final String SPACE_SEPARATOR = " ";
+
+ private static final Set DEFAULT_ALLOWED_SCHEMES = Collections.unmodifiableSet(new LinkedHashSet<>(Arrays.asList(
+ "file",
+ "jgroups",
+ "t3",
+ "t3s",
+ "tcp",
+ "ssl",
+ "udp",
+ "vm"
+ )));
+
+ private final Set allowedSchemes;
+
+ JndiJmsProviderUrlValidator() {
+ final String allowed = System.getProperty(URL_SCHEMES_ALLOWED_PROPERTY);
+ if (allowed == null || allowed.isEmpty()) {
+ allowedSchemes = DEFAULT_ALLOWED_SCHEMES;
+ } else {
+ allowedSchemes = Arrays.stream(allowed.split(SPACE_SEPARATOR)).collect(Collectors.toSet());
+ }
+ }
+
+ @Override
+ public ValidationResult validate(final String subject, final String input, final ValidationContext context) {
+ final ValidationResult.Builder builder = new ValidationResult.Builder().subject(subject).input(input);
+
+ if (input == null || input.isEmpty()) {
+ builder.valid(false);
+ builder.explanation("URL is required");
+ } else if (isUrlAllowed(input)) {
+ builder.valid(true);
+ builder.explanation("URL scheme allowed");
+ } else {
+ builder.valid(false);
+ final String explanation = String.format("URL scheme not allowed. Allowed URL schemes include %s", allowedSchemes);
+ builder.explanation(explanation);
+ }
+
+ return builder.build();
+ }
+
+ private boolean isUrlAllowed(final String input) {
+ final boolean allowed;
+
+ final Matcher matcher = URL_SCHEME_PATTERN.matcher(input);
+ if (matcher.matches()) {
+ final String scheme = matcher.group(SCHEME_GROUP);
+ allowed = isSchemeAllowed(scheme);
+ } else {
+ allowed = true;
+ }
+
+ return allowed;
+ }
+
+ private boolean isSchemeAllowed(final String scheme) {
+ boolean allowed = false;
+
+ for (final String allowedScheme : allowedSchemes) {
+ if (allowedScheme.contains(scheme)) {
+ allowed = true;
+ break;
+ }
+ }
+
+ return allowed;
+ }
+ }
}
diff --git a/nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/main/resources/docs/org.apache.nifi.jms.cf.JndiJmsConnectionFactoryProvider/additionalDetails.html b/nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/main/resources/docs/org.apache.nifi.jms.cf.JndiJmsConnectionFactoryProvider/additionalDetails.html
index eeff65d353..d29113c394 100644
--- a/nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/main/resources/docs/org.apache.nifi.jms.cf.JndiJmsConnectionFactoryProvider/additionalDetails.html
+++ b/nifi-nar-bundles/nifi-jms-bundle/nifi-jms-processors/src/main/resources/docs/org.apache.nifi.jms.cf.JndiJmsConnectionFactoryProvider/additionalDetails.html
@@ -21,9 +21,9 @@
-Description:
+Capabilities
- This ControllerService allows users to reference a JMS Connection Factory that has already been established and
+ This Controller Service allows users to reference a JMS Connection Factory that has already been established and
made available via Java Naming and Directory Interface (JNDI) Server. Please see documentation from your JMS Vendor in order
to understand the appropriate values to configure for this service.
@@ -55,7 +55,7 @@ ConnectionFactory connectionFactory = initialContext.lookup(JNDI_CONNECTION_FACT
-Example:
+Example Configuration
As an example, the following configuration may be used to connect to Active MQ's JMS Broker, using the Connection Factory provided via their embedded JNDI server:
@@ -91,5 +91,53 @@ ConnectionFactory connectionFactory = initialContext.lookup(JNDI_CONNECTION_FACT
the jar(s) containing the org.apache.activemq.jndi.ActiveMQInitialContextFactory class and the other JMS client classes can be found within the /opt/apache-activemq-5.15.2/lib/ directory.
+Property Validation
+
+
+ The following component properties include additional validation to restrict allowed values:
+
+
+
+
+JNDI Provider URL Validation
+
+
+ The default validation for JNDI Provider URL
allows the following URL schemes:
+
+
+
+ - file
+ - jgroups
+ - ssl
+ - t3
+ - t3s
+ - tcp
+ - udp
+ - vm
+
+
+
+ The following Java System property can be configured to override the default allowed URL schemes:
+
+
+
+ -
+
org.apache.nifi.jms.cf.jndi.provider.url.schemes.allowed
+
+
+
+
+ The System property must contain a space-separated list of URL schemes. This property can be configured in the application
+ bootstrap.conf
as follows:
+
+
+
+ -
+
java.arg.jndiJmsUrlSchemesAllowed=-Dorg.apache.nifi.jms.cf.jndi.provider.url.schemes.allowed=ssl tcp
+
+
+