Skip to content

Commit 91a837f

Browse files
authored
feat(nifi): Patch root placeholder in static custom auth file (#1358)
* init patch * wip: replaceWithRootGroupId * replace root ID via callback * re-parse flow * consolidate patches * corrected save action * add property for root name and patch 2.6.0 * correct/consolidate stringutils usage * changelog
1 parent 1501b24 commit 91a837f

File tree

3 files changed

+388
-0
lines changed

3 files changed

+388
-0
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ All notable changes to this project will be documented in this file.
99
- superset: Add 6.0.0-rc2 ([#1337]).
1010
- hive: Build [hive-metastore-opa-authorizer](https://github.com/boschglobal/hive-metastore-opa-authorizer) from source and add to image ([#1340]).
1111
- hive: Add `4.2.0` ([#1356]).
12+
- nifi: Add patches to replace process group root ID placeholder ([#1358]).
1213

1314
### Changed
1415

@@ -28,6 +29,7 @@ All notable changes to this project will be documented in this file.
2829
[#1354]: https://github.com/stackabletech/docker-images/pull/1354
2930
[#1356]: https://github.com/stackabletech/docker-images/pull/1356
3031
[#1357]: https://github.com/stackabletech/docker-images/pull/1357
32+
[#1358]: https://github.com/stackabletech/docker-images/pull/1358
3133

3234
## [25.11.0] - 2025-11-07
3335

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
From ed80d426e85c7b741d865f866092e89b61742c10 Mon Sep 17 00:00:00 2001
2+
From: Andrew Kenworthy <[email protected]>
3+
Date: Fri, 10 Oct 2025 15:28:56 +0200
4+
Subject: replace process groups root with root ID
5+
6+
---
7+
.../org/apache/nifi/util/NiFiProperties.java | 3 ++
8+
.../nifi/flow/FlowInitializationCallback.java | 9 ++++
9+
.../FileAccessPolicyProvider.java | 43 +++++++++++++++++++
10+
.../FileAuthorizerInitializer.java | 25 +++++++++++
11+
.../nifi/controller/StandardFlowService.java | 17 ++++++++
12+
5 files changed, 97 insertions(+)
13+
create mode 100644 nifi-framework-api/src/main/java/org/apache/nifi/flow/FlowInitializationCallback.java
14+
create mode 100644 nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizerInitializer.java
15+
16+
diff --git a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
17+
index 4bd2f4f810..24d31960b7 100644
18+
--- a/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
19+
+++ b/nifi-commons/nifi-properties/src/main/java/org/apache/nifi/util/NiFiProperties.java
20+
@@ -336,6 +336,9 @@ public class NiFiProperties extends ApplicationProperties {
21+
// performance tracking defaults
22+
public static final int DEFAULT_TRACK_PERFORMANCE_PERCENTAGE = 0;
23+
24+
+ // root process group replacement
25+
+ public static final String ROOT_PROCESS_GROUP_PLACEHOLDER ="nifi.process.group.root.placeholder";
26+
+
27+
// defaults
28+
public static final Boolean DEFAULT_AUTO_RESUME_STATE = true;
29+
public static final String DEFAULT_AUTHORIZER_CONFIGURATION_FILE = "conf/authorizers.xml";
30+
diff --git a/nifi-framework-api/src/main/java/org/apache/nifi/flow/FlowInitializationCallback.java b/nifi-framework-api/src/main/java/org/apache/nifi/flow/FlowInitializationCallback.java
31+
new file mode 100644
32+
index 0000000000..3039c97497
33+
--- /dev/null
34+
+++ b/nifi-framework-api/src/main/java/org/apache/nifi/flow/FlowInitializationCallback.java
35+
@@ -0,0 +1,9 @@
36+
+package org.apache.nifi.flow;
37+
+
38+
+/**
39+
+ * Simple callback interface invoked when the root process group has been
40+
+ * loaded and the flow is fully initialized for the first time.
41+
+ */
42+
+public interface FlowInitializationCallback {
43+
+ void onRootGroupLoaded();
44+
+}
45+
diff --git a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
46+
index 5363bb5619..a03a18d444 100644
47+
--- a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
48+
+++ b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
49+
@@ -29,6 +29,7 @@ import org.apache.nifi.authorization.resource.ResourceType;
50+
import org.apache.nifi.authorization.util.IdentityMapping;
51+
import org.apache.nifi.authorization.util.IdentityMappingUtil;
52+
import org.apache.nifi.components.PropertyValue;
53+
+import org.apache.nifi.controller.StandardFlowService;
54+
import org.apache.nifi.util.FlowInfo;
55+
import org.apache.nifi.util.FlowParser;
56+
import org.apache.nifi.util.NiFiProperties;
57+
@@ -77,6 +78,8 @@ import java.util.concurrent.atomic.AtomicReference;
58+
import java.util.regex.Matcher;
59+
import java.util.regex.Pattern;
60+
61+
+import static org.apache.nifi.util.NiFiProperties.ROOT_PROCESS_GROUP_PLACEHOLDER;
62+
+
63+
public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvider {
64+
65+
private static final Logger logger = LoggerFactory.getLogger(FileAccessPolicyProvider.class);
66+
@@ -133,6 +136,9 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
67+
public void initialize(AccessPolicyProviderInitializationContext initializationContext) throws AuthorizerCreationException {
68+
userGroupProviderLookup = initializationContext.getUserGroupProviderLookup();
69+
70+
+ // Register flow initialization hook
71+
+ StandardFlowService.registerInitializationCallback(new FileAuthorizerInitializer(this));
72+
+
73+
try {
74+
final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
75+
authorizationsSchema = schemaFactory.newSchema(FileAccessPolicyProvider.class.getResource(AUTHORIZATIONS_XSD));
76+
@@ -744,6 +750,43 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
77+
}
78+
}
79+
80+
+ /**
81+
+ * Replaces process group root references with the process group ID.
82+
+ * Relevant when a static authorizations file is provided, which can
83+
+ * then use "root" as a placeholder.
84+
+ */
85+
+ public void replaceWithRootGroupId() throws JAXBException {
86+
+ String placeholder = this.properties.getProperty(ROOT_PROCESS_GROUP_PLACEHOLDER, "");
87+
+
88+
+ if (StringUtils.isNotBlank(placeholder)) {
89+
+ if (rootGroupId == null) {
90+
+ logger.info("Parsing flow as rootGroupId is not yet defined");
91+
+ parseFlow();
92+
+ }
93+
+ if (rootGroupId != null) {
94+
+ logger.info("Parsing root group with {}", rootGroupId);
95+
+ Authorizations authorizations = this.authorizationsHolder.get().getAuthorizations();
96+
+ boolean authorizationsChanged = false;
97+
+ for (Policy policy: authorizations.getPolicies().getPolicy()) {
98+
+ String resource = policy.getResource();
99+
+ String processGroupRoot = ResourceType.ProcessGroup.getValue() + "/" + placeholder;
100+
+ if (resource.endsWith(processGroupRoot)) {
101+
+ int pos = resource.indexOf(processGroupRoot);
102+
+ policy.setResource(resource.substring(0, pos) + ResourceType.ProcessGroup.getValue() + "/" + rootGroupId);
103+
+ authorizationsChanged = true;
104+
+ }
105+
+ }
106+
+ if (authorizationsChanged) {
107+
+ saveAndRefreshHolder(authorizations);
108+
+ }
109+
+ } else {
110+
+ // this is not expected as this is called from the flow service
111+
+ // once it has been configured
112+
+ logger.info("rootGroupId still not established!");
113+
+ }
114+
+ }
115+
+ }
116+
+
117+
/**
118+
* Creates and adds an access policy for the given resource, group identity, and actions to the specified authorizations.
119+
*
120+
diff --git a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizerInitializer.java b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizerInitializer.java
121+
new file mode 100644
122+
index 0000000000..f67328ef84
123+
--- /dev/null
124+
+++ b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizerInitializer.java
125+
@@ -0,0 +1,25 @@
126+
+package org.apache.nifi.authorization;
127+
+
128+
+import org.apache.nifi.flow.FlowInitializationCallback;
129+
+import org.slf4j.Logger;
130+
+import org.slf4j.LoggerFactory;
131+
+
132+
+
133+
+public class FileAuthorizerInitializer implements FlowInitializationCallback {
134+
+ private static final Logger logger = LoggerFactory.getLogger(FileAuthorizerInitializer.class);
135+
+private FileAccessPolicyProvider fileAccessPolicyProvider;
136+
+
137+
+ public FileAuthorizerInitializer(FileAccessPolicyProvider fileAccessPolicyProvider) {
138+
+ this.fileAccessPolicyProvider = fileAccessPolicyProvider;
139+
+ }
140+
+
141+
+ @Override
142+
+ public void onRootGroupLoaded() {
143+
+ try {
144+
+ logger.info("Flow initialized; ensuring root group ID is recorded in authorizations.xml");
145+
+ this.fileAccessPolicyProvider.replaceWithRootGroupId();
146+
+ } catch (Exception e) {
147+
+ logger.warn("Unable to update authorizations.xml with root group ID", e);
148+
+ }
149+
+ }
150+
+}
151+
\ No newline at end of file
152+
diff --git a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java
153+
index 09f4d38f77..b0137c8302 100644
154+
--- a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java
155+
+++ b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java
156+
@@ -55,6 +55,7 @@ import org.apache.nifi.controller.serialization.FlowSynchronizationException;
157+
import org.apache.nifi.controller.status.ProcessGroupStatus;
158+
import org.apache.nifi.engine.FlowEngine;
159+
import org.apache.nifi.events.BulletinFactory;
160+
+import org.apache.nifi.flow.FlowInitializationCallback;
161+
import org.apache.nifi.groups.BundleUpdateStrategy;
162+
import org.apache.nifi.groups.ProcessGroup;
163+
import org.apache.nifi.groups.RemoteProcessGroup;
164+
@@ -148,6 +149,13 @@ public class StandardFlowService implements FlowService, ProtocolHandler {
165+
private static final String CONNECTION_EXCEPTION_MSG_PREFIX = "Failed to connect node to cluster";
166+
private static final Logger logger = LoggerFactory.getLogger(StandardFlowService.class);
167+
168+
+ // Static callback registration for post-initialization hooks
169+
+ private static volatile FlowInitializationCallback initializationCallback;
170+
+
171+
+ public static void registerInitializationCallback(FlowInitializationCallback callback) {
172+
+ initializationCallback = callback;
173+
+ }
174+
+
175+
public static StandardFlowService createStandaloneInstance(
176+
final FlowController controller,
177+
final NiFiProperties nifiProperties,
178+
@@ -933,6 +941,15 @@ public class StandardFlowService implements FlowService, ProtocolHandler {
179+
// start the processors as indicated by the dataflow
180+
controller.onFlowInitialized(autoResumeState);
181+
182+
+ // this should be done once the flow has been initialized
183+
+ if (initializationCallback != null) {
184+
+ try {
185+
+ initializationCallback.onRootGroupLoaded();
186+
+ } catch (Exception e) {
187+
+ logger.warn("Error invoking FlowInitializationCallback", e);
188+
+ }
189+
+ }
190+
+
191+
loadSnippets(dataFlow.getSnippets());
192+
193+
controller.startHeartbeating();

0 commit comments

Comments
 (0)