1- From 7d3774380339871ab4890b898eb35e4a8d4fc995 Mon Sep 17 00:00:00 2001
1+ From 775a7fcb5c9828b5b9077c2cccf7f300de65bd45 Mon Sep 17 00:00:00 2001
22From: Andrew Kenworthy <andrew.kenworthy@stackable.tech>
33Date: Fri, 10 Oct 2025 15:28:56 +0200
44Subject: replace process groups root with root ID
55
66---
7- .../FileAccessPolicyProvider.java | 24 +++++++++++++++++++
8- .../nifi/controller/StandardFlowService.java | 5 ++++
9- 2 files changed, 29 insertions(+)
7+ .../nifi/flow/FlowInitializationCallback.java | 9 +++++
8+ .../FileAccessPolicyProvider.java | 37 +++++++++++++++++++
9+ .../FileAuthorizerInitializer.java | 25 +++++++++++++
10+ .../nifi/controller/StandardFlowService.java | 17 +++++++++
11+ 4 files changed, 88 insertions(+)
12+ create mode 100644 nifi-framework-api/src/main/java/org/apache/nifi/flow/FlowInitializationCallback.java
13+ create mode 100644 nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizerInitializer.java
1014
15+ 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
16+ new file mode 100644
17+ index 0000000000..3039c97497
18+ --- /dev/null
19+ +++ b/nifi-framework-api/src/main/java/org/apache/nifi/flow/FlowInitializationCallback.java
20+ @@ -0,0 +1,9 @@
21+ + package org.apache.nifi.flow;
22+ +
23+ + /**
24+ + * Simple callback interface invoked when the root process group has been
25+ + * loaded and the flow is fully initialized for the first time.
26+ + */
27+ + public interface FlowInitializationCallback {
28+ + void onRootGroupLoaded();
29+ + }
1130diff --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
12- index 5363bb5619..ca9758f32c 100644
31+ index 5363bb5619..17b3f3929d 100644
1332--- a/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
1433+++ b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAccessPolicyProvider.java
15- @@ -744,6 +744,30 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
34+ @@ -29,6 +29,7 @@ import org.apache.nifi.authorization.resource.ResourceType;
35+ import org.apache.nifi.authorization.util.IdentityMapping;
36+ import org.apache.nifi.authorization.util.IdentityMappingUtil;
37+ import org.apache.nifi.components.PropertyValue;
38+ + import org.apache.nifi.controller.StandardFlowService;
39+ import org.apache.nifi.util.FlowInfo;
40+ import org.apache.nifi.util.FlowParser;
41+ import org.apache.nifi.util.NiFiProperties;
42+ @@ -133,6 +134,9 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
43+ public void initialize(AccessPolicyProviderInitializationContext initializationContext) throws AuthorizerCreationException {
44+ userGroupProviderLookup = initializationContext.getUserGroupProviderLookup();
45+
46+ + // Register flow initialization hook
47+ + StandardFlowService.registerInitializationCallback(new FileAuthorizerInitializer(this));
48+ +
49+ try {
50+ final SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
51+ authorizationsSchema = schemaFactory.newSchema(FileAccessPolicyProvider.class.getResource(AUTHORIZATIONS_XSD));
52+ @@ -744,6 +748,39 @@ public class FileAccessPolicyProvider implements ConfigurableAccessPolicyProvide
1653 }
1754 }
1855
@@ -22,7 +59,12 @@ index 5363bb5619..ca9758f32c 100644
2259+ * then use "root" as a placeholder.
2360+ */
2461+ public void replaceWithRootGroupId() throws JAXBException {
62+ + if (rootGroupId == null) {
63+ + logger.info("Parsing flow as rootGroupId is not yet defined");
64+ + parseFlow();
65+ + }
2566+ if (rootGroupId != null) {
67+ + logger.info("Parsing root group with {}", rootGroupId);
2668+ Authorizations authorizations = this.authorizationsHolder.get().getAuthorizations();
2769+ boolean authorizationsChanged = false;
2870+ for (Policy policy: authorizations.getPolicies().getPolicy()) {
@@ -37,23 +79,85 @@ index 5363bb5619..ca9758f32c 100644
3779+ if (authorizationsChanged) {
3880+ saveAuthorizations(authorizations);
3981+ }
82+ + } else {
83+ + // this is not expected as this is called from the flow service
84+ + // once it has been configured
85+ + logger.info("rootGroupId still not established!");
4086+ }
4187+ }
4288+
4389 /**
4490 * Creates and adds an access policy for the given resource, group identity, and actions to the specified authorizations.
4591 *
92+ 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
93+ new file mode 100644
94+ index 0000000000..f67328ef84
95+ --- /dev/null
96+ +++ b/nifi-framework-bundle/nifi-framework/nifi-file-authorizer/src/main/java/org/apache/nifi/authorization/FileAuthorizerInitializer.java
97+ @@ -0,0 +1,25 @@
98+ + package org.apache.nifi.authorization;
99+ +
100+ + import org.apache.nifi.flow.FlowInitializationCallback;
101+ + import org.slf4j.Logger;
102+ + import org.slf4j.LoggerFactory;
103+ +
104+ +
105+ + public class FileAuthorizerInitializer implements FlowInitializationCallback {
106+ + private static final Logger logger = LoggerFactory.getLogger(FileAuthorizerInitializer.class);
107+ + private FileAccessPolicyProvider fileAccessPolicyProvider;
108+ +
109+ + public FileAuthorizerInitializer(FileAccessPolicyProvider fileAccessPolicyProvider) {
110+ + this.fileAccessPolicyProvider = fileAccessPolicyProvider;
111+ + }
112+ +
113+ + @Override
114+ + public void onRootGroupLoaded() {
115+ + try {
116+ + logger.info("Flow initialized; ensuring root group ID is recorded in authorizations.xml");
117+ + this.fileAccessPolicyProvider.replaceWithRootGroupId();
118+ + } catch (Exception e) {
119+ + logger.warn("Unable to update authorizations.xml with root group ID", e);
120+ + }
121+ + }
122+ + }
123+ \ No newline at end of file
46124diff --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
47- index 09f4d38f77..dad44540de 100644
125+ index 09f4d38f77..b0137c8302 100644
48126--- a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java
49127+++ b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/StandardFlowService.java
50- @@ -933,6 +933,11 @@ public class StandardFlowService implements FlowService, ProtocolHandler {
128+ @@ -55,6 +55,7 @@ import org.apache.nifi.controller.serialization.FlowSynchronizationException;
129+ import org.apache.nifi.controller.status.ProcessGroupStatus;
130+ import org.apache.nifi.engine.FlowEngine;
131+ import org.apache.nifi.events.BulletinFactory;
132+ + import org.apache.nifi.flow.FlowInitializationCallback;
133+ import org.apache.nifi.groups.BundleUpdateStrategy;
134+ import org.apache.nifi.groups.ProcessGroup;
135+ import org.apache.nifi.groups.RemoteProcessGroup;
136+ @@ -148,6 +149,13 @@ public class StandardFlowService implements FlowService, ProtocolHandler {
137+ private static final String CONNECTION_EXCEPTION_MSG_PREFIX = "Failed to connect node to cluster";
138+ private static final Logger logger = LoggerFactory.getLogger(StandardFlowService.class);
139+
140+ + // Static callback registration for post-initialization hooks
141+ + private static volatile FlowInitializationCallback initializationCallback;
142+ +
143+ + public static void registerInitializationCallback(FlowInitializationCallback callback) {
144+ + initializationCallback = callback;
145+ + }
146+ +
147+ public static StandardFlowService createStandaloneInstance(
148+ final FlowController controller,
149+ final NiFiProperties nifiProperties,
150+ @@ -933,6 +941,15 @@ public class StandardFlowService implements FlowService, ProtocolHandler {
51151 // start the processors as indicated by the dataflow
52152 controller.onFlowInitialized(autoResumeState);
53153
54154+ // this should be done once the flow has been initialized
55- + if (this.authorizer instanceof org.apache.nifi.authorization.FileAccessPolicyProvider) {
56- + ((org.apache.nifi.authorization.FileAccessPolicyProvider) this.authorizer).replaceWithRootGroupId();
155+ + if (initializationCallback != null) {
156+ + try {
157+ + initializationCallback.onRootGroupLoaded();
158+ + } catch (Exception e) {
159+ + logger.warn("Error invoking FlowInitializationCallback", e);
160+ + }
57161+ }
58162+
59163 loadSnippets(dataFlow.getSnippets());
0 commit comments