This is an automated email from the ASF dual-hosted git repository.

pvillard31 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 725a2d5696d NIFI-16366 Improved validation for CS referencing 
components updates (#11694)
725a2d5696d is described below

commit 725a2d5696d3b47586f1cffa45f79f7698b2622c
Author: David Handermann <[email protected]>
AuthorDate: Fri Sep 18 13:36:41 2026 -0500

    NIFI-16366 Improved validation for CS referencing components updates 
(#11694)
---
 .../nifi/authorization/AuthorizableLookup.java     |  10 ++
 ...rizeControllerServiceReferencingComponents.java |  90 ++++++++++
 .../authorization/StandardAuthorizableLookup.java  |   6 +
 .../nifi/web/api/ControllerServiceResource.java    |  17 +-
 ...ControllerServiceReferencingComponentsTest.java | 189 +++++++++++++++++++++
 .../StandardAuthorizableLookupTest.java            |  23 +++
 6 files changed, 327 insertions(+), 8 deletions(-)

diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/AuthorizableLookup.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/AuthorizableLookup.java
index 418d2165594..0da07b2a76d 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/AuthorizableLookup.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/AuthorizableLookup.java
@@ -22,6 +22,7 @@ import org.apache.nifi.components.ConfigurableComponent;
 import org.apache.nifi.parameter.ParameterContext;
 import org.apache.nifi.web.api.dto.BundleDTO;
 
+import java.util.List;
 import java.util.Set;
 import java.util.function.Predicate;
 
@@ -213,6 +214,15 @@ public interface AuthorizableLookup {
      */
     Authorizable getControllerServiceReferencingComponent(String 
controllerServiceId, String id);
 
+    /**
+     * Get the authorizables for components of the requested type that 
reference the specified Controller Service
+     *
+     * @param controllerServiceId controller service id
+     * @param componentType type of referencing component to be returned
+     * @return referencing component authorizables
+     */
+    List<Authorizable> getControllerServiceReferencingComponents(String 
controllerServiceId, Class<? extends Authorizable> componentType);
+
     /**
      * Get the authorizable ReportingTask.
      *
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/AuthorizeControllerServiceReferencingComponents.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/AuthorizeControllerServiceReferencingComponents.java
new file mode 100644
index 00000000000..d8dceb6e5f2
--- /dev/null
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/AuthorizeControllerServiceReferencingComponents.java
@@ -0,0 +1,90 @@
+/*
+ * 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.authorization;
+
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.resource.OperationAuthorizable;
+import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.controller.FlowAnalysisRuleNode;
+import org.apache.nifi.controller.ProcessorNode;
+import org.apache.nifi.controller.ReportingTaskNode;
+import org.apache.nifi.controller.ScheduledState;
+import org.apache.nifi.controller.service.ControllerServiceNode;
+import org.apache.nifi.controller.service.ControllerServiceState;
+
+import java.util.List;
+
+/**
+ * Authorizes updates to components that reference a Controller Service.
+ */
+public final class AuthorizeControllerServiceReferencingComponents {
+
+    /**
+     * Authorizes operation of the Controller Service together with each 
component that the requested state change
+     * affects. Referencing Controller Services are authorized when a 
Controller Service state is requested. Referencing
+     * Processors, Reporting Tasks, and Flow Analysis Rules are authorized 
when a scheduled state is requested. The
+     * referencing components are resolved from the Controller Service 
reference graph, matching the components that the
+     * requested state change updates.
+     *
+     * @param authorizer authorizer
+     * @param lookup lookup
+     * @param controllerServiceId controller service id
+     * @param controllerServiceState requested Controller Service state or 
null when not requested
+     * @param scheduledState requested scheduled state or null when not 
requested
+     * @param user user
+     */
+    public static void authorize(
+            final Authorizer authorizer,
+            final AuthorizableLookup lookup,
+            final String controllerServiceId,
+            final ControllerServiceState controllerServiceState,
+            final ScheduledState scheduledState,
+            final NiFiUser user) {
+
+        final Authorizable controllerService = 
lookup.getControllerService(controllerServiceId).getAuthorizable();
+        OperationAuthorizable.authorizeOperation(controllerService, 
authorizer, user);
+
+        if (controllerServiceState != null) {
+            authorizeReferencingComponents(authorizer, lookup, 
controllerServiceId, user, ControllerServiceNode.class);
+            return;
+        }
+
+        if (scheduledState == null) {
+            return;
+        }
+
+        authorizeReferencingComponents(authorizer, lookup, 
controllerServiceId, user, ProcessorNode.class);
+        authorizeReferencingComponents(authorizer, lookup, 
controllerServiceId, user, ReportingTaskNode.class);
+        authorizeReferencingComponents(authorizer, lookup, 
controllerServiceId, user, FlowAnalysisRuleNode.class);
+    }
+
+    private static void authorizeReferencingComponents(
+            final Authorizer authorizer,
+            final AuthorizableLookup lookup,
+            final String controllerServiceId,
+            final NiFiUser user,
+            final Class<? extends Authorizable> componentType) {
+
+        final List<Authorizable> referencingComponents = 
lookup.getControllerServiceReferencingComponents(controllerServiceId, 
componentType);
+        for (final Authorizable referencingComponent : referencingComponents) {
+            OperationAuthorizable.authorizeOperation(referencingComponent, 
authorizer, user);
+        }
+    }
+
+    private AuthorizeControllerServiceReferencingComponents() {
+    }
+}
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/StandardAuthorizableLookup.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/StandardAuthorizableLookup.java
index ce67307d4ad..7e74bcf2bef 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/StandardAuthorizableLookup.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/StandardAuthorizableLookup.java
@@ -531,6 +531,12 @@ public class StandardAuthorizableLookup implements 
AuthorizableLookup {
         return reference;
     }
 
+    @Override
+    public List<Authorizable> getControllerServiceReferencingComponents(final 
String controllerServiceId, final Class<? extends Authorizable> componentType) {
+        final ControllerServiceNode controllerService = 
controllerServiceDAO.getControllerService(controllerServiceId);
+        return 
List.copyOf(controllerService.getReferences().findRecursiveReferences(componentType));
+    }
+
     @Override
     public ComponentAuthorizable getReportingTask(final String id) {
         final ReportingTaskNode reportingTaskNode = 
reportingTaskDAO.getReportingTask(id);
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java
index 9b2d7988afe..5d19e82c797 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java
@@ -43,6 +43,7 @@ import 
org.apache.nifi.authorization.AuthorizeComponentAnalysis;
 import org.apache.nifi.authorization.AuthorizeComponentReference;
 import org.apache.nifi.authorization.AuthorizeConfigVerification;
 import org.apache.nifi.authorization.AuthorizeControllerServiceReference;
+import 
org.apache.nifi.authorization.AuthorizeControllerServiceReferencingComponents;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.ComponentAuthorizable;
 import org.apache.nifi.authorization.RequestAction;
@@ -569,6 +570,10 @@ public class ControllerServiceResource extends 
ApplicationResource {
             throw new IllegalArgumentException("The controller service 
identifier must be specified.");
         }
 
+        if (!id.equals(requestUpdateReferenceRequest.getId())) {
+            throw new IllegalArgumentException("The controller service 
identifier in the request must match the identifier provided in the URL");
+        }
+
         if (requestUpdateReferenceRequest.getReferencingComponentRevisions() 
== null) {
             throw new IllegalArgumentException("The controller service 
referencing components revisions must be specified.");
         }
@@ -623,13 +628,9 @@ public class ControllerServiceResource extends 
ApplicationResource {
                 serviceFacade,
                 requestUpdateReferenceRequest,
                 requestRevisions,
-                lookup -> {
-                    requestReferencingRevisions.entrySet().stream().forEach(e 
-> {
-                        final Authorizable controllerService = 
lookup.getControllerServiceReferencingComponent(id, e.getKey());
-                        
OperationAuthorizable.authorizeOperation(controllerService, authorizer, 
NiFiUserUtils.getNiFiUser());
-                    });
-                },
-                () -> 
serviceFacade.verifyUpdateControllerServiceReferencingComponents(requestUpdateReferenceRequest.getId(),
 verifyScheduledState, verifyControllerServiceState),
+                lookup -> 
AuthorizeControllerServiceReferencingComponents.authorize(
+                        authorizer, lookup, id, verifyControllerServiceState, 
verifyScheduledState, NiFiUserUtils.getNiFiUser()),
+                () -> 
serviceFacade.verifyUpdateControllerServiceReferencingComponents(id, 
verifyScheduledState, verifyControllerServiceState),
                 (revisions, updateReferenceRequest) -> {
                     ScheduledState scheduledState = null;
                     try {
@@ -651,7 +652,7 @@ public class ControllerServiceResource extends 
ApplicationResource {
 
                     // update the controller service references
                     final ControllerServiceReferencingComponentsEntity entity 
= serviceFacade.updateControllerServiceReferencingComponents(
-                            referencingRevisions, 
updateReferenceRequest.getId(), scheduledState, controllerServiceState);
+                            referencingRevisions, id, scheduledState, 
controllerServiceState);
 
                     if (updateReferenceRequest.getUiOnly() == Boolean.TRUE) {
                         
entity.getControllerServiceReferencingComponents().forEach(this::stripNonUiRelevantFields);
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/authorization/AuthorizeControllerServiceReferencingComponentsTest.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/authorization/AuthorizeControllerServiceReferencingComponentsTest.java
new file mode 100644
index 00000000000..5295c709321
--- /dev/null
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/authorization/AuthorizeControllerServiceReferencingComponentsTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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.authorization;
+
+import org.apache.nifi.authorization.resource.Authorizable;
+import org.apache.nifi.authorization.resource.ResourceFactory;
+import org.apache.nifi.authorization.resource.ResourceType;
+import org.apache.nifi.authorization.user.NiFiUser;
+import org.apache.nifi.authorization.user.StandardNiFiUser;
+import org.apache.nifi.controller.FlowAnalysisRuleNode;
+import org.apache.nifi.controller.ProcessorNode;
+import org.apache.nifi.controller.ReportingTaskNode;
+import org.apache.nifi.controller.ScheduledState;
+import org.apache.nifi.controller.service.ControllerServiceNode;
+import org.apache.nifi.controller.service.ControllerServiceState;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class AuthorizeControllerServiceReferencingComponentsTest {
+
+    private static final String CONTROLLER_SERVICE_ID = 
"controller-service-id";
+
+    private static final String REFERENCING_SERVICE_ID = 
"referencing-service-id";
+
+    private final NiFiUser user = new 
StandardNiFiUser.Builder().identity("unit-test-user").build();
+
+    @Mock
+    private Authorizer authorizer;
+
+    @Mock
+    private AuthorizableLookup lookup;
+
+    @Mock
+    private ComponentAuthorizable controllerServiceAuthorizable;
+
+    @Mock
+    private Authorizable controllerService;
+
+    @Mock
+    private Authorizable referencingService;
+
+    @Mock
+    private Authorizable referencingProcessor;
+
+    @Mock
+    private Authorizable referencingReportingTask;
+
+    @Mock
+    private Authorizable referencingFlowAnalysisRule;
+
+    @Test
+    void 
testAuthorizeControllerServiceStateAuthorizesServiceAndReferencingServices() {
+        stubControllerService();
+        
when(lookup.getControllerServiceReferencingComponents(CONTROLLER_SERVICE_ID, 
ControllerServiceNode.class))
+                .thenReturn(List.of(referencingService));
+
+        AuthorizeControllerServiceReferencingComponents.authorize(
+                authorizer, lookup, CONTROLLER_SERVICE_ID, 
ControllerServiceState.ENABLED, ScheduledState.DISABLED, user);
+
+        verify(controllerService).authorize(authorizer, RequestAction.WRITE, 
user);
+        verify(referencingService).authorize(authorizer, RequestAction.WRITE, 
user);
+        verify(lookup, 
never()).getControllerServiceReferencingComponents(eq(CONTROLLER_SERVICE_ID), 
eq(ProcessorNode.class));
+        verify(lookup, 
never()).getControllerServiceReferencingComponents(eq(CONTROLLER_SERVICE_ID), 
eq(ReportingTaskNode.class));
+        verify(lookup, 
never()).getControllerServiceReferencingComponents(eq(CONTROLLER_SERVICE_ID), 
eq(FlowAnalysisRuleNode.class));
+    }
+
+    @Test
+    void 
testAuthorizeScheduledStateAuthorizesServiceAndReferencingSchedulableComponents()
 {
+        stubControllerService();
+        
when(lookup.getControllerServiceReferencingComponents(CONTROLLER_SERVICE_ID, 
ProcessorNode.class))
+                .thenReturn(List.of(referencingProcessor));
+        
when(lookup.getControllerServiceReferencingComponents(CONTROLLER_SERVICE_ID, 
ReportingTaskNode.class))
+                .thenReturn(List.of(referencingReportingTask));
+        
when(lookup.getControllerServiceReferencingComponents(CONTROLLER_SERVICE_ID, 
FlowAnalysisRuleNode.class))
+                .thenReturn(List.of(referencingFlowAnalysisRule));
+
+        AuthorizeControllerServiceReferencingComponents.authorize(
+                authorizer, lookup, CONTROLLER_SERVICE_ID, null, 
ScheduledState.RUNNING, user);
+
+        verify(controllerService).authorize(authorizer, RequestAction.WRITE, 
user);
+        verify(referencingProcessor).authorize(authorizer, 
RequestAction.WRITE, user);
+        verify(referencingReportingTask).authorize(authorizer, 
RequestAction.WRITE, user);
+        verify(referencingFlowAnalysisRule).authorize(authorizer, 
RequestAction.WRITE, user);
+        verify(lookup, 
never()).getControllerServiceReferencingComponents(eq(CONTROLLER_SERVICE_ID), 
eq(ControllerServiceNode.class));
+    }
+
+    @Test
+    void testAuthorizeEveryReferencingComponentEvaluated() {
+        stubControllerService();
+        
when(lookup.getControllerServiceReferencingComponents(CONTROLLER_SERVICE_ID, 
ProcessorNode.class))
+                .thenReturn(List.of(referencingProcessor, 
referencingFlowAnalysisRule));
+        
when(lookup.getControllerServiceReferencingComponents(CONTROLLER_SERVICE_ID, 
ReportingTaskNode.class))
+                .thenReturn(List.of(referencingReportingTask));
+        
when(lookup.getControllerServiceReferencingComponents(CONTROLLER_SERVICE_ID, 
FlowAnalysisRuleNode.class))
+                .thenReturn(List.of());
+
+        AuthorizeControllerServiceReferencingComponents.authorize(
+                authorizer, lookup, CONTROLLER_SERVICE_ID, null, 
ScheduledState.STOPPED, user);
+
+        verify(referencingProcessor).authorize(authorizer, 
RequestAction.WRITE, user);
+        verify(referencingFlowAnalysisRule).authorize(authorizer, 
RequestAction.WRITE, user);
+        verify(referencingReportingTask).authorize(authorizer, 
RequestAction.WRITE, user);
+    }
+
+    @Test
+    void testAuthorizeDeniedControllerService() {
+        stubControllerService();
+        denyOperation(controllerService, CONTROLLER_SERVICE_ID);
+
+        assertThrows(AccessDeniedException.class, () -> 
AuthorizeControllerServiceReferencingComponents.authorize(
+                authorizer, lookup, CONTROLLER_SERVICE_ID, 
ControllerServiceState.ENABLED, null, user));
+
+        verify(lookup, 
never()).getControllerServiceReferencingComponents(anyString(), any());
+    }
+
+    @Test
+    void testAuthorizeDeniedReferencingComponent() {
+        stubControllerService();
+        
when(lookup.getControllerServiceReferencingComponents(CONTROLLER_SERVICE_ID, 
ControllerServiceNode.class))
+                .thenReturn(List.of(referencingService));
+        denyOperation(referencingService, REFERENCING_SERVICE_ID);
+
+        assertThrows(AccessDeniedException.class, () -> 
AuthorizeControllerServiceReferencingComponents.authorize(
+                authorizer, lookup, CONTROLLER_SERVICE_ID, 
ControllerServiceState.DISABLED, null, user));
+    }
+
+    @Test
+    void testAuthorizeWithoutRequestedState() {
+        stubControllerService();
+
+        AuthorizeControllerServiceReferencingComponents.authorize(authorizer, 
lookup, CONTROLLER_SERVICE_ID, null, null, user);
+
+        verify(controllerService).authorize(authorizer, RequestAction.WRITE, 
user);
+        verify(lookup, 
never()).getControllerServiceReferencingComponents(anyString(), any());
+    }
+
+    @Test
+    void testAuthorizeWithoutReferencingComponents() {
+        stubControllerService();
+        
when(lookup.getControllerServiceReferencingComponents(CONTROLLER_SERVICE_ID, 
ControllerServiceNode.class))
+                .thenReturn(List.of());
+
+        AuthorizeControllerServiceReferencingComponents.authorize(
+                authorizer, lookup, CONTROLLER_SERVICE_ID, 
ControllerServiceState.ENABLED, null, user);
+
+        verify(controllerService).authorize(authorizer, RequestAction.WRITE, 
user);
+    }
+
+    private void stubControllerService() {
+        
when(lookup.getControllerService(CONTROLLER_SERVICE_ID)).thenReturn(controllerServiceAuthorizable);
+        
when(controllerServiceAuthorizable.getAuthorizable()).thenReturn(controllerService);
+    }
+
+    private void denyOperation(final Authorizable authorizable, final String 
identifier) {
+        doThrow(new AccessDeniedException("Access is denied"))
+                .when(authorizable).authorize(authorizer, RequestAction.WRITE, 
user);
+        when(authorizable.getResource())
+                
.thenReturn(ResourceFactory.getComponentResource(ResourceType.ControllerService,
 identifier, "Controller Service"));
+        
when(authorizer.authorize(any())).thenReturn(AuthorizationResult.denied("Access 
is denied"));
+    }
+}
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/authorization/StandardAuthorizableLookupTest.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/authorization/StandardAuthorizableLookupTest.java
index 1d8facc2745..a911a3e99f9 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/authorization/StandardAuthorizableLookupTest.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/authorization/StandardAuthorizableLookupTest.java
@@ -30,6 +30,8 @@ import org.apache.nifi.connectable.Connection;
 import org.apache.nifi.controller.FlowAnalysisRuleNode;
 import org.apache.nifi.controller.ParameterProviderNode;
 import org.apache.nifi.controller.ProcessorNode;
+import org.apache.nifi.controller.service.ControllerServiceNode;
+import org.apache.nifi.controller.service.ControllerServiceReference;
 import org.apache.nifi.groups.ProcessGroup;
 import org.apache.nifi.nar.ExtensionDiscoveringManager;
 import org.apache.nifi.nar.ExtensionManager;
@@ -39,6 +41,7 @@ import org.apache.nifi.web.controller.ControllerFacade;
 import org.apache.nifi.web.dao.ConnectionDAO;
 import org.apache.nifi.web.dao.ConnectorDAO;
 import org.apache.nifi.web.dao.ConnectorManagedComponentLookup;
+import org.apache.nifi.web.dao.ControllerServiceDAO;
 import org.apache.nifi.web.dao.FlowAnalysisRuleDAO;
 import org.apache.nifi.web.dao.FlowRegistryDAO;
 import org.apache.nifi.web.dao.ParameterProviderDAO;
@@ -46,6 +49,7 @@ import org.apache.nifi.web.dao.ProcessGroupDAO;
 import org.apache.nifi.web.dao.ProcessorDAO;
 import org.junit.jupiter.api.Test;
 
+import java.util.List;
 import java.util.Optional;
 import java.util.Set;
 
@@ -95,6 +99,25 @@ public class StandardAuthorizableLookupTest {
         assertInstanceOf(ProcessorNode.class, ((OperationAuthorizable) 
authorizable).getBaseAuthorizable());
     }
 
+    @Test
+    void 
testGetControllerServiceReferencingComponentsResolvesRecursiveReferencesForRequestedType()
 {
+        final StandardAuthorizableLookup lookup = getLookup();
+        final ControllerServiceDAO controllerServiceDAO = 
mock(ControllerServiceDAO.class);
+        final ControllerServiceNode controllerService = 
mock(ControllerServiceNode.class);
+        final ControllerServiceReference references = 
mock(ControllerServiceReference.class);
+        final ControllerServiceNode referencingService = 
mock(ControllerServiceNode.class);
+        final ProcessorNode referencingProcessor = mock(ProcessorNode.class);
+
+        
when(controllerServiceDAO.getControllerService(eq(COMPONENT_ID))).thenReturn(controllerService);
+        when(controllerService.getReferences()).thenReturn(references);
+        
when(references.findRecursiveReferences(eq(ControllerServiceNode.class))).thenReturn(List.of(referencingService));
+        
when(references.findRecursiveReferences(eq(ProcessorNode.class))).thenReturn(List.of(referencingProcessor));
+        lookup.setControllerServiceDAO(controllerServiceDAO);
+
+        assertEquals(List.of(referencingService), 
lookup.getControllerServiceReferencingComponents(COMPONENT_ID, 
ControllerServiceNode.class));
+        assertEquals(List.of(referencingProcessor), 
lookup.getControllerServiceReferencingComponents(COMPONENT_ID, 
ProcessorNode.class));
+    }
+
     @Test
     void testGetAuthorizableFromResourceController() {
         final StandardAuthorizableLookup lookup = getLookup();

Reply via email to