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

mcgilman 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 f30f877fb3e NIFI-15875 Standardize Authorization for Verify 
Configuration Methods (#11179)
f30f877fb3e is described below

commit f30f877fb3e0e2a0db7850be8b6d586203860a45
Author: David Handermann <[email protected]>
AuthorDate: Fri May 1 09:28:47 2026 -0500

    NIFI-15875 Standardize Authorization for Verify Configuration Methods 
(#11179)
    
    * NIFI-15875 Standardized Authorization for Verify Configuration Methods
    
    - Added AuthorizeConfigVerification class for shared component 
authorization handling
    
    * NIFI-15875 Added Parameter Reference authorization
---
 .../authorization/AuthorizeConfigVerification.java |  84 +++++++++++
 .../apache/nifi/web/api/ControllerResource.java    |  15 +-
 .../nifi/web/api/ControllerServiceResource.java    |  13 +-
 .../nifi/web/api/ParameterProviderResource.java    |  13 +-
 .../org/apache/nifi/web/api/ProcessorResource.java |  13 +-
 .../apache/nifi/web/api/ReportingTaskResource.java |  13 +-
 .../AuthorizeConfigVerificationTest.java           | 154 +++++++++++++++++++++
 7 files changed, 266 insertions(+), 39 deletions(-)

diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/AuthorizeConfigVerification.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/AuthorizeConfigVerification.java
new file mode 100644
index 00000000000..cb37b90d0d3
--- /dev/null
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/AuthorizeConfigVerification.java
@@ -0,0 +1,84 @@
+/*
+ * 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.user.NiFiUser;
+import org.apache.nifi.authorization.user.NiFiUserUtils;
+import org.apache.nifi.parameter.ParameterContext;
+
+import java.util.Map;
+
+/**
+ * Authorizes configuration-verification requests for any component type that 
supports verification.
+ * Requires WRITE on the target component, plus READ on any Controller 
Services referenced by
+ * the proposed properties.
+ */
+public final class AuthorizeConfigVerification {
+
+    private AuthorizeConfigVerification() {
+    }
+
+    /**
+     * Authorize a configuration-verification request against a single 
ComponentAuthorizable
+     *
+     * @param authorizer Authorizer used for determining results
+     * @param lookup Authorizable Lookup used to resolve referenced Controller 
Services
+     * @param component Component whose configuration is being verified
+     * @param proposedProperties Properties submitted for verification
+     */
+    public static void authorize(
+            final Authorizer authorizer,
+            final AuthorizableLookup lookup,
+            final ComponentAuthorizable component,
+            final Map<String, String> proposedProperties
+    ) {
+        authorize(authorizer, lookup, component, proposedProperties, null);
+    }
+
+    /**
+     * Authorize a configuration-verification request against a single 
ComponentAuthorizable with an optional ancestor
+     *
+     * @param authorizer Authorizer used for determining results
+     * @param lookup Authorizable Lookup used to resolve referenced Controller 
Services
+     * @param component Component whose configuration is being verified
+     * @param proposedProperties Properties submitted for verification
+     * @param ancestor optional parent Authorizable that must also be 
authorized
+     */
+    public static void authorize(
+            final Authorizer authorizer,
+            final AuthorizableLookup lookup,
+            final ComponentAuthorizable component,
+            final Map<String, String> proposedProperties,
+            final Authorizable ancestor
+    ) {
+        final NiFiUser user = NiFiUserUtils.getNiFiUser();
+
+        if (ancestor != null) {
+            ancestor.authorize(authorizer, RequestAction.WRITE, user);
+        }
+
+        component.getAuthorizable().authorize(authorizer, RequestAction.WRITE, 
user);
+
+        
AuthorizeControllerServiceReference.authorizeControllerServiceReferences(proposedProperties,
 component, authorizer, lookup);
+
+        final ParameterContext parameterContext = 
component.getParameterContext();
+        if (parameterContext != null) {
+            
AuthorizeParameterReference.authorizeParameterReferences(proposedProperties, 
authorizer, parameterContext, user);
+        }
+    }
+}
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
index c552084bdb1..78f4c97a048 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerResource.java
@@ -41,6 +41,7 @@ import jakarta.ws.rs.core.Response;
 import jakarta.ws.rs.core.StreamingOutput;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.AuthorizeComponentReference;
+import org.apache.nifi.authorization.AuthorizeConfigVerification;
 import org.apache.nifi.authorization.AuthorizeControllerServiceReference;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.ComponentAuthorizable;
@@ -1252,7 +1253,9 @@ public class ControllerResource extends 
ApplicationResource {
                     "issuing a GET request to 
/flow-analysis-rules/{taskId}/verification-requests/{requestId}. Once the 
request is completed, the client is expected to issue a DELETE request to " +
                     
"/flow-analysis-rules/{serviceId}/verification-requests/{requestId}.",
             security = {
-                    @SecurityRequirement(name = "Read - 
/flow-analysis-rules/{uuid}")
+                    @SecurityRequirement(name = "Write - /controller"),
+                    @SecurityRequirement(name = "Write - 
/flow-analysis-rules/{uuid}"),
+                    @SecurityRequirement(name = "Read - any referenced 
Controller Services - /controller-services/{uuid}")
             }
     )
     public Response submitFlowAnalysisRuleConfigVerificationRequest(
@@ -1286,7 +1289,7 @@ public class ControllerResource extends 
ApplicationResource {
         return withWriteLock(
                 serviceFacade,
                 flowAnalysisRuleConfigRequest,
-                lookup -> authorizeController(RequestAction.READ),
+                lookup -> AuthorizeConfigVerification.authorize(authorizer, 
lookup, lookup.getFlowAnalysisRule(flowAnalysisRuleId), 
requestDto.getProperties(), lookup.getController()),
                 () -> 
serviceFacade.verifyCanVerifyFlowAnalysisRuleConfig(flowAnalysisRuleId),
                 entity -> 
performAsyncFlowAnalysisRuleConfigVerification(entity, user)
         );
@@ -1596,7 +1599,8 @@ public class ControllerResource extends 
ApplicationResource {
                     + 
"/controller/registry-clients/{clientId}/config/verification-requests/{requestId}
 for status and "
                     + "DELETE the request once verification completes.",
             security = {
-                    @SecurityRequirement(name = "Read - /controller")
+                    @SecurityRequirement(name = "Write - 
/controller/registry-clients/{uuid}"),
+                    @SecurityRequirement(name = "Read - any referenced 
Controller Services - /controller-services/{uuid}")
             }
     )
     public Response submitRegistryClientConfigVerificationRequest(
@@ -1630,10 +1634,7 @@ public class ControllerResource extends 
ApplicationResource {
         return withWriteLock(
                 serviceFacade,
                 registryClientConfigRequest,
-                lookup -> {
-                    final Authorizable authorizable = 
lookup.getFlowRegistryClient(registryClientId).getAuthorizable();
-                    authorizable.authorize(authorizer, RequestAction.READ, 
user);
-                },
+                lookup -> AuthorizeConfigVerification.authorize(authorizer, 
lookup, lookup.getFlowRegistryClient(registryClientId), 
requestDto.getProperties()),
                 () -> 
serviceFacade.verifyCanVerifyFlowRegistryClientConfig(registryClientId),
                 entity -> performAsyncRegistryClientConfigVerification(entity, 
user)
         );
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 5e4110224a2..64fb165b429 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
@@ -40,6 +40,7 @@ import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.Response;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.AuthorizeComponentReference;
+import org.apache.nifi.authorization.AuthorizeConfigVerification;
 import org.apache.nifi.authorization.AuthorizeControllerServiceReference;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.ComponentAuthorizable;
@@ -993,7 +994,8 @@ public class ControllerServiceResource extends 
ApplicationResource {
                     "issuing a GET request to 
/controller-services/{serviceId}/verification-requests/{requestId}. Once the 
request is completed, the client is expected to issue a DELETE request to " +
                     
"/controller-services/{serviceId}/verification-requests/{requestId}.",
             security = {
-                    @SecurityRequirement(name = "Read - 
/controller-services/{uuid}")
+                    @SecurityRequirement(name = "Write - 
/controller-services/{uuid}"),
+                    @SecurityRequirement(name = "Read - any referenced 
Controller Services - /controller-services/{uuid}")
             }
     )
     public Response submitConfigVerificationRequest(
@@ -1027,13 +1029,8 @@ public class ControllerServiceResource extends 
ApplicationResource {
         return withWriteLock(
                 serviceFacade,
                 controllerServiceConfigRequest,
-                lookup -> {
-                    final ComponentAuthorizable controllerService = 
lookup.getControllerService(controllerServiceId);
-                    controllerService.getAuthorizable().authorize(authorizer, 
RequestAction.READ, NiFiUserUtils.getNiFiUser());
-                },
-                () -> {
-                    
serviceFacade.verifyCanVerifyControllerServiceConfig(controllerServiceId);
-                },
+                lookup -> AuthorizeConfigVerification.authorize(authorizer, 
lookup, lookup.getControllerService(controllerServiceId), 
requestDto.getProperties()),
+                () -> 
serviceFacade.verifyCanVerifyControllerServiceConfig(controllerServiceId),
                 entity -> performAsyncConfigVerification(entity, user)
         );
     }
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ParameterProviderResource.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ParameterProviderResource.java
index 23e209d5065..71eda3b6675 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ParameterProviderResource.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ParameterProviderResource.java
@@ -43,6 +43,7 @@ import jakarta.ws.rs.core.Response;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.AuthorizableLookup;
 import org.apache.nifi.authorization.AuthorizeComponentReference;
+import org.apache.nifi.authorization.AuthorizeConfigVerification;
 import org.apache.nifi.authorization.AuthorizeControllerServiceReference;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.ComponentAuthorizable;
@@ -1227,7 +1228,8 @@ public class ParameterProviderResource extends 
AbstractParameterResource {
                     "issuing a GET request to 
/parameter-providers/{serviceId}/verification-requests/{requestId}. Once the 
request is completed, the client is expected to issue a DELETE request to " +
                     
"/parameter-providers/{providerId}/verification-requests/{requestId}.",
             security = {
-                    @SecurityRequirement(name = "Read - 
/parameter-providers/{uuid}")
+                    @SecurityRequirement(name = "Write - 
/parameter-providers/{uuid}"),
+                    @SecurityRequirement(name = "Read - any referenced 
Controller Services - /controller-services/{uuid}")
             }
     )
     public Response submitConfigVerificationRequest(
@@ -1260,13 +1262,8 @@ public class ParameterProviderResource extends 
AbstractParameterResource {
         return withWriteLock(
                 serviceFacade,
                 parameterProviderConfigRequest,
-                lookup -> {
-                    final ComponentAuthorizable parameterProvider = 
lookup.getParameterProvider(parameterProviderId);
-                    parameterProvider.getAuthorizable().authorize(authorizer, 
RequestAction.READ, NiFiUserUtils.getNiFiUser());
-                },
-                () -> {
-                    
serviceFacade.verifyCanVerifyParameterProviderConfig(parameterProviderId);
-                },
+                lookup -> AuthorizeConfigVerification.authorize(authorizer, 
lookup, lookup.getParameterProvider(parameterProviderId), 
requestDto.getProperties()),
+                () -> 
serviceFacade.verifyCanVerifyParameterProviderConfig(parameterProviderId),
                 entity -> performAsyncConfigVerification(entity, user)
         );
     }
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java
index 4a10f70adaa..0a6192cd407 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessorResource.java
@@ -40,6 +40,7 @@ import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.Response;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.AuthorizeComponentReference;
+import org.apache.nifi.authorization.AuthorizeConfigVerification;
 import org.apache.nifi.authorization.AuthorizeControllerServiceReference;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.ComponentAuthorizable;
@@ -703,7 +704,8 @@ public class ProcessorResource extends ApplicationResource {
                     "issuing a GET request to 
/processors/{processorId}/verification-requests/{requestId}. Once the request 
is completed, the client is expected to issue a DELETE request to " +
                     
"/processors/{processorId}/verification-requests/{requestId}.",
             security = {
-                    @SecurityRequirement(name = "Read - /processors/{uuid}")
+                    @SecurityRequirement(name = "Write - /processors/{uuid}"),
+                    @SecurityRequirement(name = "Read - any referenced 
Controller Services - /controller-services/{uuid}")
             }
     )
     public Response submitProcessorVerificationRequest(
@@ -736,13 +738,8 @@ public class ProcessorResource extends ApplicationResource 
{
         return withWriteLock(
                 serviceFacade,
                 processorConfigRequest,
-                lookup -> {
-                    final ComponentAuthorizable processor = 
lookup.getProcessor(processorId);
-                    processor.getAuthorizable().authorize(authorizer, 
RequestAction.READ, NiFiUserUtils.getNiFiUser());
-                },
-                () -> {
-                    serviceFacade.verifyCanVerifyProcessorConfig(processorId);
-                },
+                lookup -> AuthorizeConfigVerification.authorize(authorizer, 
lookup, lookup.getProcessor(processorId), requestDto.getProperties()),
+                () -> 
serviceFacade.verifyCanVerifyProcessorConfig(processorId),
                 entity -> performAsyncConfigVerification(entity, user)
         );
     }
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ReportingTaskResource.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ReportingTaskResource.java
index 43048f161d1..a486d6e8704 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ReportingTaskResource.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ReportingTaskResource.java
@@ -40,6 +40,7 @@ import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.Response;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.nifi.authorization.AuthorizeComponentReference;
+import org.apache.nifi.authorization.AuthorizeConfigVerification;
 import org.apache.nifi.authorization.AuthorizeControllerServiceReference;
 import org.apache.nifi.authorization.Authorizer;
 import org.apache.nifi.authorization.ComponentAuthorizable;
@@ -795,7 +796,8 @@ public class ReportingTaskResource extends 
ApplicationResource {
                     "issuing a GET request to 
/reporting-tasks/{taskId}/verification-requests/{requestId}. Once the request 
is completed, the client is expected to issue a DELETE request to " +
                     
"/reporting-tasks/{serviceId}/verification-requests/{requestId}.",
             security = {
-                    @SecurityRequirement(name = "Read - 
/reporting-tasks/{uuid}")
+                    @SecurityRequirement(name = "Write - 
/reporting-tasks/{uuid}"),
+                    @SecurityRequirement(name = "Read - any referenced 
Controller Services - /controller-services/{uuid}")
             }
     )
     public Response submitConfigVerificationRequest(
@@ -828,13 +830,8 @@ public class ReportingTaskResource extends 
ApplicationResource {
         return withWriteLock(
                 serviceFacade,
                 reportingTaskConfigRequest,
-                lookup -> {
-                    final ComponentAuthorizable reportingTask = 
lookup.getReportingTask(reportingTaskId);
-                    reportingTask.getAuthorizable().authorize(authorizer, 
RequestAction.READ, NiFiUserUtils.getNiFiUser());
-                },
-                () -> {
-                    
serviceFacade.verifyCanVerifyReportingTaskConfig(reportingTaskId);
-                },
+                lookup -> AuthorizeConfigVerification.authorize(authorizer, 
lookup, lookup.getReportingTask(reportingTaskId), requestDto.getProperties()),
+                () -> 
serviceFacade.verifyCanVerifyReportingTaskConfig(reportingTaskId),
                 entity -> performAsyncConfigVerification(entity, user)
         );
     }
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/authorization/AuthorizeConfigVerificationTest.java
 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/authorization/AuthorizeConfigVerificationTest.java
new file mode 100644
index 00000000000..e87f0dd64fb
--- /dev/null
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/authorization/AuthorizeConfigVerificationTest.java
@@ -0,0 +1,154 @@
+/*
+ * 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.components.PropertyDescriptor;
+import org.apache.nifi.controller.AbstractControllerService;
+import org.apache.nifi.parameter.ParameterContext;
+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.Map;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class AuthorizeConfigVerificationTest {
+
+    private static final String PROPERTY = "URL";
+    private static final String PARAMETER_REFERENCE = "#{url}";
+    private static final String CONTROLLER_SERVICE_ID = 
"controller-service-id";
+
+    @Mock
+    private Authorizer authorizer;
+
+    @Mock
+    private AuthorizableLookup authorizableLookup;
+
+    @Mock
+    private ComponentAuthorizable componentAuthorizable;
+
+    @Mock
+    private Authorizable componentAuthorizableDelegate;
+
+    @Mock
+    private Authorizable ancestor;
+
+    @Mock
+    private PropertyDescriptor propertyDescriptor;
+
+    @Mock
+    private ParameterContext parameterContext;
+
+    @Mock
+    private ComponentAuthorizable controllerService;
+
+    @Mock
+    private Authorizable controllerServiceAuthorizable;
+
+    @Test
+    void testAuthorizeComponentWriteApproved() {
+        
when(componentAuthorizable.getAuthorizable()).thenReturn(componentAuthorizableDelegate);
+
+        AuthorizeConfigVerification.authorize(authorizer, authorizableLookup, 
componentAuthorizable, Map.of());
+
+        verify(componentAuthorizableDelegate).authorize(eq(authorizer), 
eq(RequestAction.WRITE), any());
+        verify(ancestor, never()).authorize(any(), any(), any());
+    }
+
+    @Test
+    void testAuthorizeComponentAndAncestorWriteApproved() {
+        
when(componentAuthorizable.getAuthorizable()).thenReturn(componentAuthorizableDelegate);
+
+        AuthorizeConfigVerification.authorize(authorizer, authorizableLookup, 
componentAuthorizable, Map.of(), ancestor);
+
+        verify(ancestor).authorize(eq(authorizer), eq(RequestAction.WRITE), 
any());
+        verify(componentAuthorizableDelegate).authorize(eq(authorizer), 
eq(RequestAction.WRITE), any());
+    }
+
+    @Test
+    void testAuthorizeComponentWriteParameterContextApproved() {
+        
when(componentAuthorizable.getAuthorizable()).thenReturn(componentAuthorizableDelegate);
+        
when(componentAuthorizable.getParameterContext()).thenReturn(parameterContext);
+        
when(componentAuthorizable.getPropertyDescriptor(eq(PROPERTY))).thenReturn(propertyDescriptor);
+
+        final Map<String, String> properties = Map.of(PROPERTY, 
PARAMETER_REFERENCE);
+        AuthorizeConfigVerification.authorize(authorizer, authorizableLookup, 
componentAuthorizable, properties);
+
+        verify(componentAuthorizableDelegate).authorize(eq(authorizer), 
eq(RequestAction.WRITE), any());
+        verify(ancestor, never()).authorize(any(), any(), any());
+        verify(parameterContext).authorize(eq(authorizer), 
eq(RequestAction.READ), any());
+    }
+
+    @Test
+    void testAuthorizeComponentWriteControllerServiceApproved() {
+        
when(componentAuthorizable.getAuthorizable()).thenReturn(componentAuthorizableDelegate);
+        
when(componentAuthorizable.getParameterContext()).thenReturn(parameterContext);
+        
when(componentAuthorizable.getPropertyDescriptor(eq(PROPERTY))).thenReturn(propertyDescriptor);
+        
doReturn(MockControllerService.class).when(propertyDescriptor).getControllerServiceDefinition();
+        
when(authorizableLookup.getControllerService(eq(CONTROLLER_SERVICE_ID))).thenReturn(controllerService);
+        
when(controllerService.getAuthorizable()).thenReturn(controllerServiceAuthorizable);
+
+        final Map<String, String> properties = Map.of(PROPERTY, 
CONTROLLER_SERVICE_ID);
+        AuthorizeConfigVerification.authorize(authorizer, authorizableLookup, 
componentAuthorizable, properties);
+
+        verify(componentAuthorizableDelegate).authorize(eq(authorizer), 
eq(RequestAction.WRITE), any());
+        verify(ancestor, never()).authorize(any(), any(), any());
+        verify(controllerServiceAuthorizable).authorize(eq(authorizer), 
eq(RequestAction.READ), any());
+    }
+
+    @Test
+    void testAuthorizeNullAncestorSkipped() {
+        
when(componentAuthorizable.getAuthorizable()).thenReturn(componentAuthorizableDelegate);
+
+        AuthorizeConfigVerification.authorize(authorizer, authorizableLookup, 
componentAuthorizable, Map.of(), null);
+
+        verify(componentAuthorizableDelegate).authorize(eq(authorizer), 
eq(RequestAction.WRITE), any());
+        verify(ancestor, never()).authorize(any(), any(), any());
+    }
+
+    @Test
+    void testAuthorizeComponentWriteDenied() {
+        
when(componentAuthorizable.getAuthorizable()).thenReturn(componentAuthorizableDelegate);
+        doThrow(new 
AccessDeniedException("denied")).when(componentAuthorizableDelegate).authorize(eq(authorizer),
 eq(RequestAction.WRITE), any());
+
+        assertThrows(AccessDeniedException.class, () -> 
AuthorizeConfigVerification.authorize(authorizer, authorizableLookup, 
componentAuthorizable, Map.of()));
+    }
+
+    @Test
+    void testAuthorizeAncestorWriteDenied() {
+        doThrow(new 
AccessDeniedException("denied")).when(ancestor).authorize(eq(authorizer), 
eq(RequestAction.WRITE), any());
+
+        assertThrows(AccessDeniedException.class, () -> 
AuthorizeConfigVerification.authorize(authorizer, authorizableLookup, 
componentAuthorizable, Map.of(), ancestor));
+
+        verify(componentAuthorizable, never()).getAuthorizable();
+    }
+
+    private static class MockControllerService extends 
AbstractControllerService {
+
+    }
+}

Reply via email to