This is an automated email from the ASF dual-hosted git repository.
exceptionfactory 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 60319e26f85 NIFI-16236 Validate versioned Parameter names and allow
removal of invalid Parameters (#11579)
60319e26f85 is described below
commit 60319e26f8549a6965d29feaf7c8103294882732
Author: skeossei <[email protected]>
AuthorDate: Fri Aug 21 13:33:13 2026 -0700
NIFI-16236 Validate versioned Parameter names and allow removal of invalid
Parameters (#11579)
Signed-off-by: David Handermann <[email protected]>
---
.../nifi/parameter/ParameterNameValidator.java | 33 ++++++++++++++++++
.../nifi/parameter/ParameterNameValidatorTest.java | 40 ++++++++++++++++++++++
.../serialization/VersionedFlowSynchronizer.java | 2 ++
.../VersionedFlowSynchronizerTest.java | 32 +++++++++++++++++
.../nifi/web/api/ParameterContextResource.java | 17 ++++-----
5 files changed, 116 insertions(+), 8 deletions(-)
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/parameter/ParameterNameValidator.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/parameter/ParameterNameValidator.java
new file mode 100644
index 00000000000..21bc03b268a
--- /dev/null
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/parameter/ParameterNameValidator.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.parameter;
+
+import java.util.regex.Pattern;
+
+public final class ParameterNameValidator {
+ private static final Pattern VALID_PARAMETER_NAME_PATTERN =
Pattern.compile("[A-Za-z0-9 ._\\-]+");
+
+ private ParameterNameValidator() {
+ }
+
+ public static void validate(final String parameterName) {
+ if (parameterName == null ||
!VALID_PARAMETER_NAME_PATTERN.matcher(parameterName).matches()) {
+ throw new IllegalArgumentException("Request contains an illegal
Parameter Name (" + parameterName
+ + "). Parameter names may only include letters, numbers,
spaces, and the special characters .-_");
+ }
+ }
+}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/test/java/org/apache/nifi/parameter/ParameterNameValidatorTest.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/test/java/org/apache/nifi/parameter/ParameterNameValidatorTest.java
new file mode 100644
index 00000000000..5e867c6d854
--- /dev/null
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/test/java/org/apache/nifi/parameter/ParameterNameValidatorTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.parameter;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+class ParameterNameValidatorTest {
+ @Test
+ void testValidParameterName() {
+ assertDoesNotThrow(() -> ParameterNameValidator.validate("Parameter
Name-1.0"));
+ }
+
+ @Test
+ void testInvalidParameterName() {
+ final String parameterName = "PARAMETER_{{ ENVIRONMENT }}";
+
+ final IllegalArgumentException exception =
assertThrows(IllegalArgumentException.class,
+ () -> ParameterNameValidator.validate(parameterName));
+
+ assertTrue(exception.getMessage().contains(parameterName));
+ }
+}
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/VersionedFlowSynchronizer.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/VersionedFlowSynchronizer.java
index 8036b7b7c65..3fb116e4d47 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/VersionedFlowSynchronizer.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/VersionedFlowSynchronizer.java
@@ -87,6 +87,7 @@ import org.apache.nifi.parameter.ParameterContext;
import org.apache.nifi.parameter.ParameterContextManager;
import org.apache.nifi.parameter.ParameterDescriptor;
import org.apache.nifi.parameter.ParameterGroup;
+import org.apache.nifi.parameter.ParameterNameValidator;
import org.apache.nifi.parameter.ParameterProviderConfiguration;
import org.apache.nifi.parameter.StandardParameterProviderConfiguration;
import org.apache.nifi.persistence.FlowConfigurationArchiveManager;
@@ -953,6 +954,7 @@ public class VersionedFlowSynchronizer implements
FlowSynchronizer {
final Map<String, Parameter> parameters = new HashMap<>();
for (final VersionedParameter versioned :
versionedParameterContext.getParameters()) {
+ ParameterNameValidator.validate(versioned.getName());
final boolean provided = providerBacked || versioned.isProvided();
final String parameterValue;
final String rawValue = versioned.getValue();
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/serialization/VersionedFlowSynchronizerTest.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/serialization/VersionedFlowSynchronizerTest.java
index 536bb24810d..d541e7bfabe 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/serialization/VersionedFlowSynchronizerTest.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/serialization/VersionedFlowSynchronizerTest.java
@@ -82,6 +82,7 @@ import java.util.concurrent.CompletableFuture;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -368,6 +369,37 @@ class VersionedFlowSynchronizerTest {
"Parameter value must be re-sourced from the Parameter
Provider, not the corrupted serialized value or null");
}
+ @Test
+ void testSyncRejectsInvalidParameterName() {
+ setRootGroup();
+ setFlowController();
+
+ final String invalidParameterName = "PARAMETER_{{ ENVIRONMENT }}";
+
+ final StandardParameterContextManager contextManager = new
StandardParameterContextManager();
+
when(flowManager.getParameterContextManager()).thenReturn(contextManager);
+ doAnswer(invocation -> {
+ invocation.getArgument(0, Runnable.class).run();
+ return null;
+ }).when(flowManager).withParameterContextResolution(any());
+
+ final VersionedParameter versionedParameter = new VersionedParameter();
+ versionedParameter.setName(invalidParameterName);
+ versionedParameter.setSensitive(true);
+ versionedParameter.setValue("parameter-value");
+
+ final VersionedParameterContext versionedParameterContext = new
VersionedParameterContext();
+
versionedParameterContext.setInstanceIdentifier("parameter-context-id");
+ versionedParameterContext.setName("parameter-context");
+
versionedParameterContext.setParameters(Collections.singleton(versionedParameter));
+
when(versionedDataflow.getParameterContexts()).thenReturn(List.of(versionedParameterContext));
+
+ final FlowSynchronizationException exception =
assertThrows(FlowSynchronizationException.class, () ->
+ versionedFlowSynchronizer.sync(flowController, dataFlow,
flowService, BundleUpdateStrategy.USE_SPECIFIED_OR_GHOST));
+ final IllegalArgumentException cause =
assertInstanceOf(IllegalArgumentException.class, exception.getCause());
+ assertTrue(cause.getMessage().contains(invalidParameterName));
+ }
+
private void setRootGroup() {
when(flowController.getFlowManager()).thenReturn(flowManager);
when(flowManager.getRootGroup()).thenReturn(rootGroup);
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ParameterContextResource.java
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ParameterContextResource.java
index 87e5ac45384..5409fbb8c53 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ParameterContextResource.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ParameterContextResource.java
@@ -59,6 +59,7 @@ import org.apache.nifi.cluster.protocol.NodeIdentifier;
import org.apache.nifi.controller.ComponentNode;
import org.apache.nifi.controller.ControllerService;
import org.apache.nifi.parameter.ParameterContext;
+import org.apache.nifi.parameter.ParameterNameValidator;
import org.apache.nifi.parameter.ParameterReferencedControllerServiceData;
import org.apache.nifi.processor.DataUnit;
import org.apache.nifi.stream.io.MaxLengthInputStream;
@@ -121,7 +122,6 @@ import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
-import java.util.regex.Pattern;
import java.util.stream.Collectors;
@Controller
@@ -129,7 +129,6 @@ import java.util.stream.Collectors;
@Tag(name = "ParameterContexts")
public class ParameterContextResource extends AbstractParameterResource {
private static final Logger logger =
LoggerFactory.getLogger(ParameterContextResource.class);
- private static final Pattern VALID_PARAMETER_NAME_PATTERN =
Pattern.compile("[A-Za-z0-9 ._\\-]+");
private static final String FILENAME_HEADER = "Filename";
private static final String CONTENT_TYPE_HEADER = "Content-Type";
private static final String UPLOAD_CONTENT_TYPE =
"application/octet-stream";
@@ -875,17 +874,19 @@ public class ParameterContextResource extends
AbstractParameterResource {
private void validateParameterNames(final ParameterContextDTO
parameterContextDto) {
if (parameterContextDto.getParameters() != null) {
for (final ParameterEntity entity :
parameterContextDto.getParameters()) {
- final String parameterName = entity.getParameter().getName();
- if (!isLegalParameterName(parameterName)) {
- throw new IllegalArgumentException("Request contains an
illegal Parameter Name (" + parameterName
- + "). Parameter names may only include letters,
numbers, spaces, and the special characters .-_");
+ final ParameterDTO parameter = entity.getParameter();
+ if (!isParameterDeletion(parameter)) {
+ ParameterNameValidator.validate(parameter.getName());
}
}
}
}
- private boolean isLegalParameterName(final String parameterName) {
- return VALID_PARAMETER_NAME_PATTERN.matcher(parameterName).matches();
+ private boolean isParameterDeletion(final ParameterDTO parameter) {
+ return parameter.getDescription() == null
+ && parameter.getSensitive() == null
+ && parameter.getValue() == null
+ && parameter.getReferencedAssets() == null;
}
@GET