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 1d4f8849486 NIFI-16205 Improved Connector Referenced Object
Authorization (#11547)
1d4f8849486 is described below
commit 1d4f884948655499fad6c6c406c6227239006ccb
Author: David Handermann <[email protected]>
AuthorDate: Sat Aug 15 07:59:20 2026 -0500
NIFI-16205 Improved Connector Referenced Object Authorization (#11547)
- Added Asset and Secret checking during verification
---
.../nifi/authorization/AuthorizableLookup.java | 19 ++
.../AuthorizeConnectorConfigReferences.java | 141 +++++++++++++
.../authorization/StandardAuthorizableLookup.java | 62 ++++++
.../org/apache/nifi/web/api/ConnectorResource.java | 19 +-
.../AuthorizeConnectorConfigReferencesTest.java | 224 +++++++++++++++++++++
.../StandardAuthorizableLookupTest.java | 143 +++++++++++++
.../apache/nifi/web/api/TestConnectorResource.java | 99 +++++++++
.../tests/system/connectors/ConnectorAssetsIT.java | 1 +
8 files changed, 698 insertions(+), 10 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 ff152f4f40f..418d2165594 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
@@ -333,6 +333,25 @@ public interface AuthorizableLookup {
*/
Authorizable getConnector(String connectorId);
+ /**
+ * Get the authorizable governing access to an Asset referenced by a
Connector configuration
+ *
+ * @param connectorId the ID of the connector that must own the referenced
Asset
+ * @param assetId the ID of the referenced Asset
+ * @return Authorizable for the Asset owned by the Connector
+ */
+ Authorizable getConnectorAsset(String connectorId, String assetId);
+
+ /**
+ * Get the authorizable for the Parameter Provider that backs a Secret
referenced by a connector configuration
+ *
+ * @param secretProviderId the identifier of the Parameter Provider, if
known
+ * @param secretProviderName the name of the Parameter Provider, if known
+ * @param fullyQualifiedSecretName the fully qualified Secret name, whose
leading segment identifies the provider name
+ * @return the authorizable for the Parameter Provider that backs the
referenced Secret
+ */
+ Authorizable getConnectorSecretProvider(String secretProviderId, String
secretProviderName, String fullyQualifiedSecretName);
+
/**
* Get the authorizable for access to the System resource.
*
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/AuthorizeConnectorConfigReferences.java
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/AuthorizeConnectorConfigReferences.java
new file mode 100644
index 00000000000..9927c5355cc
--- /dev/null
+++
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/authorization/AuthorizeConnectorConfigReferences.java
@@ -0,0 +1,141 @@
+/*
+ * 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.components.connector.ConnectorValueType;
+import org.apache.nifi.web.api.dto.AssetReferenceDTO;
+import org.apache.nifi.web.api.dto.ConfigurationStepConfigurationDTO;
+import org.apache.nifi.web.api.dto.ConnectorValueReferenceDTO;
+import org.apache.nifi.web.api.dto.PropertyGroupConfigurationDTO;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Authorizes a proposed Connector configuration step and the resources
referenced by its property values.
+ * Requires {@code WRITE} on the connector itself. In addition, referencing a
Secret requires {@code READ} on
+ * the backing Parameter Provider, and referencing an Asset requires {@code
READ} on the connector that owns
+ * the Asset, which enforces that the Asset belongs to the connector being
configured.
+ */
+public final class AuthorizeConnectorConfigReferences {
+
+ private AuthorizeConnectorConfigReferences() {
+ }
+
+ /**
+ * Authorize a proposed Connector configuration step, including any
resources it references.
+ *
+ * @param authorizer Authorizer used for determining results
+ * @param lookup Authorizable Lookup used to resolve the connector and any
referenced Secrets and Assets
+ * @param connectorId the identifier of the connector whose configuration
is being applied or verified
+ * @param configurationStep the proposed configuration step, whose
property values are inspected for references
+ */
+ public static void authorize(
+ final Authorizer authorizer,
+ final AuthorizableLookup lookup,
+ final String connectorId,
+ final ConfigurationStepConfigurationDTO configurationStep
+ ) {
+ final NiFiUser user = NiFiUserUtils.getNiFiUser();
+
+ lookup.getConnector(connectorId).authorize(authorizer,
RequestAction.WRITE, user);
+
+ if (configurationStep == null ||
configurationStep.getPropertyGroupConfigurations() == null) {
+ return;
+ }
+
+ for (final PropertyGroupConfigurationDTO propertyGroup :
configurationStep.getPropertyGroupConfigurations()) {
+ final Map<String, ConnectorValueReferenceDTO> propertyValues =
propertyGroup.getPropertyValues();
+ if (propertyValues == null) {
+ continue;
+ }
+
+ for (final ConnectorValueReferenceDTO valueReference :
propertyValues.values()) {
+ authorizeValueReference(authorizer, lookup, connectorId,
valueReference, user);
+ }
+ }
+ }
+
+ private static void authorizeValueReference(
+ final Authorizer authorizer,
+ final AuthorizableLookup lookup,
+ final String connectorId,
+ final ConnectorValueReferenceDTO valueReference,
+ final NiFiUser user
+ ) {
+ if (valueReference == null || valueReference.getValueType() == null) {
+ return;
+ }
+
+ final ConnectorValueType valueType;
+ try {
+ valueType =
ConnectorValueType.valueOf(valueReference.getValueType());
+ } catch (final IllegalArgumentException e) {
+ throw new IllegalArgumentException("Unknown Connector Value Type:
" + valueReference.getValueType());
+ }
+
+ switch (valueType) {
+ case STRING_LITERAL -> {
+ // String literals do not reference any externally authorized
resource.
+ }
+ case ASSET_REFERENCE -> authorizeAssetReferences(authorizer,
lookup, connectorId, valueReference.getAssetReferences(), user);
+ case SECRET_REFERENCE -> authorizeSecretReference(authorizer,
lookup, valueReference, user);
+ }
+ }
+
+ private static void authorizeAssetReferences(
+ final Authorizer authorizer,
+ final AuthorizableLookup lookup,
+ final String connectorId,
+ final List<AssetReferenceDTO> assetReferences,
+ final NiFiUser user
+ ) {
+ if (assetReferences == null || assetReferences.isEmpty()) {
+ throw new IllegalArgumentException("Asset references must be
specified when value type is ASSET_REFERENCE");
+ }
+
+ for (final AssetReferenceDTO assetReference : assetReferences) {
+ if (assetReference == null) {
+ throw new IllegalArgumentException("Asset reference must be
specified");
+ }
+
+ final String assetId = assetReference.getId();
+ if (assetId == null || assetId.isEmpty()) {
+ throw new IllegalArgumentException("Asset reference identifier
must be specified");
+ }
+
+ final Authorizable assetAuthorizable =
lookup.getConnectorAsset(connectorId, assetId);
+ assetAuthorizable.authorize(authorizer, RequestAction.READ, user);
+ }
+ }
+
+ private static void authorizeSecretReference(
+ final Authorizer authorizer,
+ final AuthorizableLookup lookup,
+ final ConnectorValueReferenceDTO valueReference,
+ final NiFiUser user
+ ) {
+ final Authorizable secretProvider = lookup.getConnectorSecretProvider(
+ valueReference.getSecretProviderId(),
+ valueReference.getSecretProviderName(),
+ valueReference.getFullyQualifiedSecretName());
+ secretProvider.authorize(authorizer, RequestAction.READ, user);
+ }
+}
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 ad3258a0818..ce67307d4ad 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
@@ -17,6 +17,7 @@
package org.apache.nifi.authorization;
import org.apache.commons.lang3.StringUtils;
+import org.apache.nifi.asset.Asset;
import org.apache.nifi.authorization.resource.AccessPolicyAuthorizable;
import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.authorization.resource.DataAuthorizable;
@@ -87,6 +88,8 @@ import java.util.stream.Collectors;
@Component
public class StandardAuthorizableLookup implements AuthorizableLookup {
+ private static final String SECRET_PROVIDER_NOT_FOUND_MESSAGE = "The
Parameter Provider for the referenced Secret could not be found";
+
private static final TenantAuthorizable TENANT_AUTHORIZABLE = new
TenantAuthorizable();
private static final Authorizable POLICIES_AUTHORIZABLE = new
Authorizable() {
@@ -709,6 +712,65 @@ public class StandardAuthorizableLookup implements
AuthorizableLookup {
return connectorDAO.getConnector(connectorId,
ConnectorSyncMode.LOCAL_ONLY);
}
+ @Override
+ public Authorizable getConnectorAsset(final String connectorId, final
String assetId) {
+ final Asset asset = connectorDAO.getAsset(assetId).orElseThrow(() ->
new ResourceNotFoundException("Asset [%s] not found".formatted(assetId)));
+ if (connectorId.equals(asset.getOwnerIdentifier())) {
+ return getConnector(connectorId);
+ } else {
+ throw new ResourceNotFoundException("Asset [%s] not
found".formatted(assetId));
+ }
+ }
+
+ @Override
+ public Authorizable getConnectorSecretProvider(final String
secretProviderId, final String secretProviderName, final String
fullyQualifiedSecretName) {
+ if (secretProviderId != null && !secretProviderId.isEmpty()) {
+ try {
+ return
parameterProviderDAO.getParameterProvider(secretProviderId);
+ } catch (final ResourceNotFoundException e) {
+ throw new
ResourceNotFoundException(SECRET_PROVIDER_NOT_FOUND_MESSAGE);
+ }
+ }
+
+ final String resolvedSecretProviderName =
getResolvedSecretProviderName(secretProviderName, fullyQualifiedSecretName);
+ final List<ParameterProviderNode> matchingProviders =
parameterProviderDAO.getParameterProviders().stream()
+ .filter(node ->
resolvedSecretProviderName.equals(node.getName()))
+ .toList();
+
+ if (matchingProviders.isEmpty()) {
+ throw new
ResourceNotFoundException(SECRET_PROVIDER_NOT_FOUND_MESSAGE);
+ }
+ if (matchingProviders.size() > 1) {
+ throw new IllegalArgumentException("Multiple Parameter Providers
found [%s] Parameter Provider ID
required".formatted(resolvedSecretProviderName));
+ }
+
+ return matchingProviders.getFirst();
+ }
+
+ private String getResolvedSecretProviderName(final String
secretProviderName, final String fullyQualifiedSecretName) {
+ final String resolvedSecretProviderName;
+ if (secretProviderName == null || secretProviderName.isEmpty()) {
+ if (fullyQualifiedSecretName == null) {
+ resolvedSecretProviderName = null;
+ } else {
+ final int providerNameEndIndex =
fullyQualifiedSecretName.indexOf('.');
+ if (providerNameEndIndex > 0) {
+ resolvedSecretProviderName =
fullyQualifiedSecretName.substring(0, providerNameEndIndex);
+ } else {
+ resolvedSecretProviderName = null;
+ }
+ }
+ } else {
+ resolvedSecretProviderName = secretProviderName;
+ }
+
+ if (resolvedSecretProviderName == null) {
+ throw new
ResourceNotFoundException(SECRET_PROVIDER_NOT_FOUND_MESSAGE);
+ }
+ return resolvedSecretProviderName;
+ }
+
+
private Authorizable handleResourceTypeContainingOtherResourceType(final
String resource, final ResourceType resourceType) {
// get the resource type
final String baseResource = StringUtils.substringAfter(resource,
resourceType.getValue());
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectorResource.java
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectorResource.java
index 7836582db82..c0de37b3f76 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectorResource.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ConnectorResource.java
@@ -47,6 +47,7 @@ import jakarta.ws.rs.core.StreamingOutput;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.nifi.asset.Asset;
+import org.apache.nifi.authorization.AuthorizeConnectorConfigReferences;
import org.apache.nifi.authorization.Authorizer;
import org.apache.nifi.authorization.RequestAction;
import org.apache.nifi.authorization.resource.Authorizable;
@@ -1403,7 +1404,9 @@ public class ConnectorResource extends
ApplicationResource {
@ApiResponse(responseCode = "409", description = "The
request was valid but NiFi was not in the appropriate state to process it.")
},
security = {
- @SecurityRequirement(name = "Write - /connectors/{uuid}")
+ @SecurityRequirement(name = "Write - /connectors/{uuid}"),
+ @SecurityRequirement(name = "Read - any referenced
Parameter Providers - /parameter-providers/{uuid}"),
+ @SecurityRequirement(name = "Read - /connectors/{uuid}
when referencing Assets owned by the connector")
}
)
public Response updateConnectorConfigurationStep(
@@ -1458,10 +1461,7 @@ public class ConnectorResource extends
ApplicationResource {
serviceFacade,
requestConfigurationStepEntity,
requestRevision,
- lookup -> {
- final Authorizable connector = lookup.getConnector(id);
- connector.authorize(authorizer, RequestAction.WRITE,
NiFiUserUtils.getNiFiUser());
- },
+ lookup ->
AuthorizeConnectorConfigReferences.authorize(authorizer, lookup, id,
requestConfigurationStep),
() -> {
// Verify the connector exists and the configuration step
exists
serviceFacade.getConnectorConfigurationStep(id,
configurationStepName);
@@ -1507,7 +1507,9 @@ public class ConnectorResource extends
ApplicationResource {
"/connectors/{connectorId}/configuration-steps/{stepName}/verify-config/{requestId}.
Once the request is completed, the client is expected to issue a DELETE
request to " +
"/connectors/{connectorId}/configuration-steps/{stepName}/verify-config/{requestId}.",
security = {
- @SecurityRequirement(name = "Write - /connectors/{uuid}")
+ @SecurityRequirement(name = "Write - /connectors/{uuid}"),
+ @SecurityRequirement(name = "Read - any referenced
Parameter Providers - /parameter-providers/{uuid}"),
+ @SecurityRequirement(name = "Read - /connectors/{uuid}
when referencing Assets owned by the connector")
}
)
public Response submitConfigurationStepVerificationRequest(
@@ -1552,10 +1554,7 @@ public class ConnectorResource extends
ApplicationResource {
return withWriteLock(
serviceFacade,
requestEntity,
- lookup -> {
- final Authorizable connector = lookup.getConnector(id);
- connector.authorize(authorizer, RequestAction.WRITE,
NiFiUserUtils.getNiFiUser());
- },
+ lookup ->
AuthorizeConnectorConfigReferences.authorize(authorizer, lookup, id,
requestDto.getConfigurationStep()),
() -> {
serviceFacade.verifyCanVerifyConnectorConfigurationStep(id,
configurationStepName);
},
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/authorization/AuthorizeConnectorConfigReferencesTest.java
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/authorization/AuthorizeConnectorConfigReferencesTest.java
new file mode 100644
index 00000000000..3a4b762c017
--- /dev/null
+++
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/authorization/AuthorizeConnectorConfigReferencesTest.java
@@ -0,0 +1,224 @@
+/*
+ * 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.connector.ConnectorValueType;
+import org.apache.nifi.web.api.dto.AssetReferenceDTO;
+import org.apache.nifi.web.api.dto.ConfigurationStepConfigurationDTO;
+import org.apache.nifi.web.api.dto.ConnectorValueReferenceDTO;
+import org.apache.nifi.web.api.dto.PropertyGroupConfigurationDTO;
+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 java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.any;
+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 AuthorizeConnectorConfigReferencesTest {
+
+ private static final String CONNECTOR_ID = "connector-1";
+ private static final String SECRET_PROVIDER_ID = "parameter-provider-1";
+ private static final String SECRET_PROVIDER_NAME = "Vault Provider";
+ private static final String SECRET_NAME = "api-key";
+ private static final String FULLY_QUALIFIED_SECRET_NAME =
SECRET_PROVIDER_NAME + "." + SECRET_NAME;
+ private static final String ASSET_ID = "asset-1";
+ private static final String PROPERTY_GROUP_NAME = "authentication";
+ private static final String PROPERTY_NAME = "password";
+
+ @Mock
+ private Authorizer authorizer;
+
+ @Mock
+ private AuthorizableLookup lookup;
+
+ @Mock
+ private Authorizable connectorAuthorizable;
+
+ @Mock
+ private Authorizable secretProviderAuthorizable;
+
+ @Mock
+ private Authorizable assetAuthorizable;
+
+ @Test
+ void testAuthorizesConnectorWriteWithNoReferences() {
+
when(lookup.getConnector(eq(CONNECTOR_ID))).thenReturn(connectorAuthorizable);
+
+ AuthorizeConnectorConfigReferences.authorize(authorizer, lookup,
CONNECTOR_ID, new ConfigurationStepConfigurationDTO());
+
+ verify(connectorAuthorizable).authorize(eq(authorizer),
eq(RequestAction.WRITE), any());
+ }
+
+ @Test
+ void testAuthorizesSecretReferenceReadOnProvider() {
+
when(lookup.getConnector(eq(CONNECTOR_ID))).thenReturn(connectorAuthorizable);
+ when(lookup.getConnectorSecretProvider(eq(SECRET_PROVIDER_ID),
eq(SECRET_PROVIDER_NAME), eq(FULLY_QUALIFIED_SECRET_NAME)))
+ .thenReturn(secretProviderAuthorizable);
+
+ final ConfigurationStepConfigurationDTO configurationStep =
configurationStepWithValue(secretReference());
+ AuthorizeConnectorConfigReferences.authorize(authorizer, lookup,
CONNECTOR_ID, configurationStep);
+
+ verify(connectorAuthorizable).authorize(eq(authorizer),
eq(RequestAction.WRITE), any());
+ verify(secretProviderAuthorizable).authorize(eq(authorizer),
eq(RequestAction.READ), any());
+ }
+
+ @Test
+ void testAuthorizesAssetReferenceReadOnOwningConnector() {
+
when(lookup.getConnector(eq(CONNECTOR_ID))).thenReturn(connectorAuthorizable);
+ when(lookup.getConnectorAsset(eq(CONNECTOR_ID),
eq(ASSET_ID))).thenReturn(assetAuthorizable);
+
+ final ConfigurationStepConfigurationDTO configurationStep =
configurationStepWithValue(assetReference());
+ AuthorizeConnectorConfigReferences.authorize(authorizer, lookup,
CONNECTOR_ID, configurationStep);
+
+ verify(connectorAuthorizable).authorize(eq(authorizer),
eq(RequestAction.WRITE), any());
+ verify(assetAuthorizable).authorize(eq(authorizer),
eq(RequestAction.READ), any());
+ }
+
+ @Test
+ void testIgnoresStringLiterals() {
+
when(lookup.getConnector(eq(CONNECTOR_ID))).thenReturn(connectorAuthorizable);
+
+ final ConnectorValueReferenceDTO stringLiteral = new
ConnectorValueReferenceDTO();
+
stringLiteral.setValueType(ConnectorValueType.STRING_LITERAL.toString());
+ stringLiteral.setValue("plain-text");
+
+ AuthorizeConnectorConfigReferences.authorize(authorizer, lookup,
CONNECTOR_ID, configurationStepWithValue(stringLiteral));
+
+ verify(connectorAuthorizable).authorize(eq(authorizer),
eq(RequestAction.WRITE), any());
+ verify(lookup, never()).getConnectorSecretProvider(any(), any(),
any());
+ verify(lookup, never()).getConnectorAsset(any(), any());
+ }
+
+ @Test
+ void testConnectorWriteDeniedSkipsReferenceResolution() {
+
when(lookup.getConnector(eq(CONNECTOR_ID))).thenReturn(connectorAuthorizable);
+ doThrow(new
AccessDeniedException("denied")).when(connectorAuthorizable).authorize(eq(authorizer),
eq(RequestAction.WRITE), any());
+
+ final ConfigurationStepConfigurationDTO configurationStep =
configurationStepWithValue(secretReference());
+
+ assertThrows(AccessDeniedException.class,
+ () -> AuthorizeConnectorConfigReferences.authorize(authorizer,
lookup, CONNECTOR_ID, configurationStep));
+
+ verify(lookup, never()).getConnectorSecretProvider(any(), any(),
any());
+ }
+
+ @Test
+ void testSecretProviderReadDenied() {
+
when(lookup.getConnector(eq(CONNECTOR_ID))).thenReturn(connectorAuthorizable);
+ when(lookup.getConnectorSecretProvider(eq(SECRET_PROVIDER_ID),
eq(SECRET_PROVIDER_NAME), eq(FULLY_QUALIFIED_SECRET_NAME)))
+ .thenReturn(secretProviderAuthorizable);
+ doThrow(new
AccessDeniedException("denied")).when(secretProviderAuthorizable).authorize(eq(authorizer),
eq(RequestAction.READ), any());
+
+ final ConfigurationStepConfigurationDTO configurationStep =
configurationStepWithValue(secretReference());
+
+ assertThrows(AccessDeniedException.class,
+ () -> AuthorizeConnectorConfigReferences.authorize(authorizer,
lookup, CONNECTOR_ID, configurationStep));
+ }
+
+ @Test
+ void testUnknownValueTypeRejected() {
+
when(lookup.getConnector(eq(CONNECTOR_ID))).thenReturn(connectorAuthorizable);
+
+ final ConnectorValueReferenceDTO unknown = new
ConnectorValueReferenceDTO();
+ unknown.setValueType("NOT_A_REAL_TYPE");
+
+ final ConfigurationStepConfigurationDTO configurationStep =
configurationStepWithValue(unknown);
+
+ assertThrows(IllegalArgumentException.class,
+ () -> AuthorizeConnectorConfigReferences.authorize(authorizer,
lookup, CONNECTOR_ID, configurationStep));
+ }
+
+ @Test
+ void testRejectsNullAssetReferences() {
+
when(lookup.getConnector(eq(CONNECTOR_ID))).thenReturn(connectorAuthorizable);
+
+ final ConnectorValueReferenceDTO valueReference = new
ConnectorValueReferenceDTO();
+
valueReference.setValueType(ConnectorValueType.ASSET_REFERENCE.toString());
+ valueReference.setAssetReferences(null);
+
+ assertThrows(IllegalArgumentException.class,
+ () -> AuthorizeConnectorConfigReferences.authorize(authorizer,
lookup, CONNECTOR_ID, configurationStepWithValue(valueReference)));
+
+ verify(lookup, never()).getConnectorAsset(any(), any());
+ }
+
+ @Test
+ void testRejectsEmptyAssetReferences() {
+
when(lookup.getConnector(eq(CONNECTOR_ID))).thenReturn(connectorAuthorizable);
+
+ final ConnectorValueReferenceDTO valueReference = new
ConnectorValueReferenceDTO();
+
valueReference.setValueType(ConnectorValueType.ASSET_REFERENCE.toString());
+ valueReference.setAssetReferences(List.of());
+
+ assertThrows(IllegalArgumentException.class,
+ () -> AuthorizeConnectorConfigReferences.authorize(authorizer,
lookup, CONNECTOR_ID, configurationStepWithValue(valueReference)));
+
+ verify(lookup, never()).getConnectorAsset(any(), any());
+ }
+
+ @Test
+ void testRejectsNullAssetReferenceId() {
+
when(lookup.getConnector(eq(CONNECTOR_ID))).thenReturn(connectorAuthorizable);
+
+ final ConnectorValueReferenceDTO valueReference = new
ConnectorValueReferenceDTO();
+
valueReference.setValueType(ConnectorValueType.ASSET_REFERENCE.toString());
+ valueReference.setAssetReferences(List.of(new AssetReferenceDTO()));
+
+ assertThrows(IllegalArgumentException.class,
+ () -> AuthorizeConnectorConfigReferences.authorize(authorizer,
lookup, CONNECTOR_ID, configurationStepWithValue(valueReference)));
+
+ verify(lookup, never()).getConnectorAsset(any(), any());
+ }
+
+ private ConfigurationStepConfigurationDTO configurationStepWithValue(final
ConnectorValueReferenceDTO valueReference) {
+ final PropertyGroupConfigurationDTO propertyGroup = new
PropertyGroupConfigurationDTO();
+ propertyGroup.setPropertyGroupName(PROPERTY_GROUP_NAME);
+ propertyGroup.setPropertyValues(Map.of(PROPERTY_NAME, valueReference));
+
+ final ConfigurationStepConfigurationDTO configurationStep = new
ConfigurationStepConfigurationDTO();
+
configurationStep.setPropertyGroupConfigurations(List.of(propertyGroup));
+ return configurationStep;
+ }
+
+ private ConnectorValueReferenceDTO secretReference() {
+ final ConnectorValueReferenceDTO valueReference = new
ConnectorValueReferenceDTO();
+
valueReference.setValueType(ConnectorValueType.SECRET_REFERENCE.toString());
+ valueReference.setSecretProviderId(SECRET_PROVIDER_ID);
+ valueReference.setSecretProviderName(SECRET_PROVIDER_NAME);
+ valueReference.setSecretName(SECRET_NAME);
+
valueReference.setFullyQualifiedSecretName(FULLY_QUALIFIED_SECRET_NAME);
+ return valueReference;
+ }
+
+ private ConnectorValueReferenceDTO assetReference() {
+ final ConnectorValueReferenceDTO valueReference = new
ConnectorValueReferenceDTO();
+
valueReference.setValueType(ConnectorValueType.ASSET_REFERENCE.toString());
+ valueReference.setAssetReferences(List.of(new
AssetReferenceDTO(ASSET_ID)));
+ return valueReference;
+ }
+}
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 b44bc1c13a7..1d8facc2745 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
@@ -16,32 +16,44 @@
*/
package org.apache.nifi.authorization;
+import org.apache.nifi.asset.Asset;
import org.apache.nifi.authorization.resource.AccessPolicyAuthorizable;
import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.authorization.resource.DataAuthorizable;
import org.apache.nifi.authorization.resource.DataTransferAuthorizable;
import org.apache.nifi.authorization.resource.OperationAuthorizable;
import org.apache.nifi.authorization.resource.ProvenanceDataAuthorizable;
+import org.apache.nifi.components.connector.ConnectorNode;
+import org.apache.nifi.components.connector.ConnectorSyncMode;
import org.apache.nifi.connectable.Connectable;
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.groups.ProcessGroup;
import org.apache.nifi.nar.ExtensionDiscoveringManager;
import org.apache.nifi.nar.ExtensionManager;
import org.apache.nifi.registry.flow.FlowRegistryClientNode;
+import org.apache.nifi.web.ResourceNotFoundException;
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.FlowAnalysisRuleDAO;
import org.apache.nifi.web.dao.FlowRegistryDAO;
+import org.apache.nifi.web.dao.ParameterProviderDAO;
import org.apache.nifi.web.dao.ProcessGroupDAO;
import org.apache.nifi.web.dao.ProcessorDAO;
import org.junit.jupiter.api.Test;
+import java.util.Optional;
+import java.util.Set;
+
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -50,6 +62,10 @@ import static org.mockito.Mockito.when;
public class StandardAuthorizableLookupTest {
private static final String COMPONENT_ID = "id";
+ private static final String CONNECTOR_ID = "connector-1";
+ private static final String ASSET_ID = "asset-1";
+ private static final String SECRET_PROVIDER_ID = "parameter-provider-1";
+ private static final String SECRET_PROVIDER_NAME = "Vault Provider";
@Test
void testGetAuthorizableFromResource() {
@@ -179,6 +195,133 @@ public class StandardAuthorizableLookupTest {
verify(connectorManagedComponentLookup).getProcessGroup(eq(COMPONENT_ID));
}
+ @Test
+ void testGetConnectorAssetResolvesOwnedAsset() {
+ final StandardAuthorizableLookup lookup = getLookup();
+ final ConnectorDAO connectorDAO = mock(ConnectorDAO.class);
+ lookup.setConnectorDAO(connectorDAO);
+
+ final Asset asset = mock(Asset.class);
+ when(asset.getOwnerIdentifier()).thenReturn(CONNECTOR_ID);
+
when(connectorDAO.getAsset(eq(ASSET_ID))).thenReturn(Optional.of(asset));
+
+ final ConnectorNode connectorNode = mock(ConnectorNode.class);
+ when(connectorDAO.getConnector(eq(CONNECTOR_ID),
eq(ConnectorSyncMode.LOCAL_ONLY))).thenReturn(connectorNode);
+
+ final Authorizable result = lookup.getConnectorAsset(CONNECTOR_ID,
ASSET_ID);
+
+ assertSame(connectorNode, result);
+ }
+
+ @Test
+ void testGetConnectorAssetRejectsAssetOwnedByAnotherConnector() {
+ final StandardAuthorizableLookup lookup = getLookup();
+ final ConnectorDAO connectorDAO = mock(ConnectorDAO.class);
+ lookup.setConnectorDAO(connectorDAO);
+
+ final Asset asset = mock(Asset.class);
+ when(asset.getOwnerIdentifier()).thenReturn("another-connector");
+
when(connectorDAO.getAsset(eq(ASSET_ID))).thenReturn(Optional.of(asset));
+
+ assertThrows(ResourceNotFoundException.class, () ->
lookup.getConnectorAsset(CONNECTOR_ID, ASSET_ID));
+ }
+
+ @Test
+ void testGetConnectorAssetRejectsMissingAsset() {
+ final StandardAuthorizableLookup lookup = getLookup();
+ final ConnectorDAO connectorDAO = mock(ConnectorDAO.class);
+ lookup.setConnectorDAO(connectorDAO);
+
+ when(connectorDAO.getAsset(eq(ASSET_ID))).thenReturn(Optional.empty());
+
+ assertThrows(ResourceNotFoundException.class, () ->
lookup.getConnectorAsset(CONNECTOR_ID, ASSET_ID));
+ }
+
+ @Test
+ void testGetConnectorSecretProviderResolvesById() {
+ final StandardAuthorizableLookup lookup = getLookup();
+ final ParameterProviderDAO parameterProviderDAO =
mock(ParameterProviderDAO.class);
+ lookup.setParameterProviderDAO(parameterProviderDAO);
+
+ final ParameterProviderNode provider =
mock(ParameterProviderNode.class);
+
when(parameterProviderDAO.getParameterProvider(eq(SECRET_PROVIDER_ID))).thenReturn(provider);
+
+ final Authorizable result =
lookup.getConnectorSecretProvider(SECRET_PROVIDER_ID, null, null);
+
+ assertSame(provider, result);
+ }
+
+ @Test
+ void testGetConnectorSecretProviderResolvesByName() {
+ final StandardAuthorizableLookup lookup = getLookup();
+ final ParameterProviderDAO parameterProviderDAO =
mock(ParameterProviderDAO.class);
+ lookup.setParameterProviderDAO(parameterProviderDAO);
+
+ final ParameterProviderNode matchingProvider =
mock(ParameterProviderNode.class);
+ when(matchingProvider.getName()).thenReturn(SECRET_PROVIDER_NAME);
+ final ParameterProviderNode otherProvider =
mock(ParameterProviderNode.class);
+ when(otherProvider.getName()).thenReturn("Other Provider");
+
when(parameterProviderDAO.getParameterProviders()).thenReturn(Set.of(matchingProvider,
otherProvider));
+
+ final Authorizable result = lookup.getConnectorSecretProvider(null,
SECRET_PROVIDER_NAME, null);
+
+ assertSame(matchingProvider, result);
+ }
+
+ @Test
+ void testGetConnectorSecretProviderResolvesByFullyQualifiedName() {
+ final StandardAuthorizableLookup lookup = getLookup();
+ final ParameterProviderDAO parameterProviderDAO =
mock(ParameterProviderDAO.class);
+ lookup.setParameterProviderDAO(parameterProviderDAO);
+
+ final ParameterProviderNode matchingProvider =
mock(ParameterProviderNode.class);
+ when(matchingProvider.getName()).thenReturn(SECRET_PROVIDER_NAME);
+
when(parameterProviderDAO.getParameterProviders()).thenReturn(Set.of(matchingProvider));
+
+ final Authorizable result = lookup.getConnectorSecretProvider(null,
null, SECRET_PROVIDER_NAME + ".api-key");
+
+ assertSame(matchingProvider, result);
+ }
+
+ @Test
+ void testGetConnectorSecretProviderFailsWhenUnresolved() {
+ final StandardAuthorizableLookup lookup = getLookup();
+ final ParameterProviderDAO parameterProviderDAO =
mock(ParameterProviderDAO.class);
+ lookup.setParameterProviderDAO(parameterProviderDAO);
+
when(parameterProviderDAO.getParameterProviders()).thenReturn(Set.of());
+
+ assertThrows(ResourceNotFoundException.class, () ->
lookup.getConnectorSecretProvider(null, "Missing Provider", null));
+ }
+
+ @Test
+ void testGetConnectorSecretProviderMasksMissingProviderId() {
+ final StandardAuthorizableLookup lookup = getLookup();
+ final ParameterProviderDAO parameterProviderDAO =
mock(ParameterProviderDAO.class);
+ lookup.setParameterProviderDAO(parameterProviderDAO);
+ when(parameterProviderDAO.getParameterProvider(eq(SECRET_PROVIDER_ID)))
+ .thenThrow(new ResourceNotFoundException("Unable to locate
parameter provider with id '%s'.".formatted(SECRET_PROVIDER_ID)));
+
+ final ResourceNotFoundException exception =
assertThrows(ResourceNotFoundException.class,
+ () -> lookup.getConnectorSecretProvider(SECRET_PROVIDER_ID,
null, null));
+
+ assertEquals("The Parameter Provider for the referenced Secret could
not be found", exception.getMessage());
+ }
+
+ @Test
+ void testGetConnectorSecretProviderFailsWhenMultipleProvidersShareName() {
+ final StandardAuthorizableLookup lookup = getLookup();
+ final ParameterProviderDAO parameterProviderDAO =
mock(ParameterProviderDAO.class);
+ lookup.setParameterProviderDAO(parameterProviderDAO);
+
+ final ParameterProviderNode firstProvider =
mock(ParameterProviderNode.class);
+ when(firstProvider.getName()).thenReturn(SECRET_PROVIDER_NAME);
+ final ParameterProviderNode secondProvider =
mock(ParameterProviderNode.class);
+ when(secondProvider.getName()).thenReturn(SECRET_PROVIDER_NAME);
+
when(parameterProviderDAO.getParameterProviders()).thenReturn(Set.of(firstProvider,
secondProvider));
+
+ assertThrows(IllegalArgumentException.class, () ->
lookup.getConnectorSecretProvider(null, SECRET_PROVIDER_NAME, null));
+ }
+
private StandardAuthorizableLookup getLookup() {
final ExtensionManager extensionManager =
mock(ExtensionDiscoveringManager.class);
final ControllerFacade controllerFacade = mock(ControllerFacade.class);
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/TestConnectorResource.java
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/TestConnectorResource.java
index b09de3509be..fb32e890f03 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/TestConnectorResource.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/test/java/org/apache/nifi/web/api/TestConnectorResource.java
@@ -23,8 +23,11 @@ import jakarta.ws.rs.core.UriBuilder;
import jakarta.ws.rs.core.UriInfo;
import org.apache.nifi.asset.Asset;
import org.apache.nifi.authorization.AccessDeniedException;
+import org.apache.nifi.authorization.AuthorizableLookup;
import org.apache.nifi.authorization.AuthorizeAccess;
import org.apache.nifi.authorization.Authorizer;
+import org.apache.nifi.authorization.RequestAction;
+import org.apache.nifi.authorization.resource.Authorizable;
import org.apache.nifi.authorization.user.NiFiUser;
import org.apache.nifi.authorization.user.NiFiUserDetails;
import org.apache.nifi.authorization.user.StandardNiFiUser;
@@ -36,17 +39,22 @@ import org.apache.nifi.web.Revision;
import org.apache.nifi.web.api.dto.AllowableValueDTO;
import org.apache.nifi.web.api.dto.BacklogDTO;
import org.apache.nifi.web.api.dto.ComponentStateDTO;
+import org.apache.nifi.web.api.dto.ConfigurationStepConfigurationDTO;
import org.apache.nifi.web.api.dto.ConnectorDTO;
+import org.apache.nifi.web.api.dto.ConnectorValueReferenceDTO;
import org.apache.nifi.web.api.dto.MigrationRequestDTO;
import org.apache.nifi.web.api.dto.MigrationRequestLocalSourceDTO;
import org.apache.nifi.web.api.dto.ParameterContextDTO;
import org.apache.nifi.web.api.dto.ParameterDTO;
+import org.apache.nifi.web.api.dto.PropertyGroupConfigurationDTO;
import org.apache.nifi.web.api.dto.RevisionDTO;
+import org.apache.nifi.web.api.dto.VerifyConnectorConfigStepRequestDTO;
import org.apache.nifi.web.api.dto.flow.ProcessGroupFlowDTO;
import org.apache.nifi.web.api.entity.AllowableValueEntity;
import org.apache.nifi.web.api.entity.BacklogEntity;
import org.apache.nifi.web.api.entity.BacklogRequestEntity;
import org.apache.nifi.web.api.entity.ComponentStateEntity;
+import org.apache.nifi.web.api.entity.ConfigurationStepEntity;
import org.apache.nifi.web.api.entity.ConnectorEntity;
import org.apache.nifi.web.api.entity.ConnectorPropertyAllowableValuesEntity;
import org.apache.nifi.web.api.entity.ConnectorRunStatusEntity;
@@ -57,6 +65,7 @@ import org.apache.nifi.web.api.entity.ParameterContextEntity;
import org.apache.nifi.web.api.entity.ParameterEntity;
import org.apache.nifi.web.api.entity.ProcessGroupFlowEntity;
import org.apache.nifi.web.api.entity.SecretsEntity;
+import org.apache.nifi.web.api.entity.VerifyConnectorConfigStepRequestEntity;
import org.apache.nifi.web.api.entity.VersionedFlowMigrationSourcesEntity;
import org.apache.nifi.web.api.request.ClientIdParameter;
import org.apache.nifi.web.api.request.LongParameter;
@@ -78,6 +87,7 @@ import java.net.URI;
import java.nio.file.Files;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
@@ -91,6 +101,7 @@ import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.lenient;
@@ -139,6 +150,7 @@ public class TestConnectorResource {
private static final String CONFIGURATION_STEP_NAME = "test-step";
private static final String PROPERTY_GROUP_NAME = "test-group";
private static final String PROPERTY_NAME = "test-property";
+ private static final String SECRET_PROVIDER_ID = "parameter-provider-1";
private static final String PROCESS_GROUP_ID = "test-process-group-id";
private static final String PROCESSOR_ID = "test-processor-id";
private static final String CONTROLLER_SERVICE_ID =
"test-controller-service-id";
@@ -543,6 +555,93 @@ public class TestConnectorResource {
verify(serviceFacade, never()).getSecrets();
}
+ private ConfigurationStepConfigurationDTO
createConfigurationStepWithSecretReference() {
+ final ConnectorValueReferenceDTO secretReference = new
ConnectorValueReferenceDTO();
+ secretReference.setValueType("SECRET_REFERENCE");
+ secretReference.setSecretProviderId(SECRET_PROVIDER_ID);
+ secretReference.setSecretName("api-key");
+
+ final PropertyGroupConfigurationDTO propertyGroup = new
PropertyGroupConfigurationDTO();
+ propertyGroup.setPropertyGroupName(PROPERTY_GROUP_NAME);
+ propertyGroup.setPropertyValues(Map.of(PROPERTY_NAME,
secretReference));
+
+ final ConfigurationStepConfigurationDTO configurationStep = new
ConfigurationStepConfigurationDTO();
+ configurationStep.setConfigurationStepName(CONFIGURATION_STEP_NAME);
+
configurationStep.setPropertyGroupConfigurations(List.of(propertyGroup));
+ return configurationStep;
+ }
+
+ private VerifyConnectorConfigStepRequestEntity
createVerifyConfigStepRequestEntity() {
+ final VerifyConnectorConfigStepRequestDTO requestDto = new
VerifyConnectorConfigStepRequestDTO();
+ requestDto.setConnectorId(CONNECTOR_ID);
+ requestDto.setConfigurationStepName(CONFIGURATION_STEP_NAME);
+
requestDto.setConfigurationStep(createConfigurationStepWithSecretReference());
+
+ final VerifyConnectorConfigStepRequestEntity requestEntity = new
VerifyConnectorConfigStepRequestEntity();
+ requestEntity.setRequest(requestDto);
+ return requestEntity;
+ }
+
+ private ConfigurationStepEntity createUpdateConfigurationStepEntity() {
+ final RevisionDTO revision = new RevisionDTO();
+ revision.setVersion(1L);
+ revision.setClientId("client-id");
+
+ final ConfigurationStepEntity entity = new ConfigurationStepEntity();
+ entity.setParentConnectorId(CONNECTOR_ID);
+ entity.setParentConnectorRevision(revision);
+
entity.setConfigurationStep(createConfigurationStepWithSecretReference());
+ return entity;
+ }
+
+ private AuthorizableLookup wireDeniedSecretReferenceAuthorization() {
+ final AuthorizableLookup lookup = mock(AuthorizableLookup.class);
+
+ final Authorizable connector = mock(Authorizable.class);
+ when(lookup.getConnector(CONNECTOR_ID)).thenReturn(connector);
+
+ final Authorizable secretProvider = mock(Authorizable.class);
+ when(lookup.getConnectorSecretProvider(SECRET_PROVIDER_ID, null,
null)).thenReturn(secretProvider);
+ doThrow(new AccessDeniedException("Not authorized to read the
referenced secret's Parameter Provider"))
+ .when(secretProvider).authorize(any(), eq(RequestAction.READ),
any());
+
+ doAnswer(invocation -> {
+ final AuthorizeAccess authorizeAccess = invocation.getArgument(0);
+ authorizeAccess.authorize(lookup);
+ return null;
+ }).when(serviceFacade).authorizeAccess(any(AuthorizeAccess.class));
+
+ return lookup;
+ }
+
+ @Test
+ public void
testSubmitConfigStepVerificationAuthorizesReferencesBeforeVerification() {
+ authenticate();
+ final AuthorizableLookup lookup =
wireDeniedSecretReferenceAuthorization();
+
+ final VerifyConnectorConfigStepRequestEntity requestEntity =
createVerifyConfigStepRequestEntity();
+
+ assertThrows(AccessDeniedException.class,
+ () ->
connectorResource.submitConfigurationStepVerificationRequest(CONNECTOR_ID,
CONFIGURATION_STEP_NAME, requestEntity));
+
+ verify(lookup).getConnectorSecretProvider(SECRET_PROVIDER_ID, null,
null);
+ verify(serviceFacade,
never()).verifyCanVerifyConnectorConfigurationStep(anyString(), anyString());
+ verify(serviceFacade,
never()).performConnectorConfigurationStepVerification(anyString(),
anyString(), any());
+ }
+
+ @Test
+ public void testUpdateConfigStepAuthorizesReferencesBeforeUpdate() {
+ final AuthorizableLookup lookup =
wireDeniedSecretReferenceAuthorization();
+
+ final ConfigurationStepEntity requestEntity =
createUpdateConfigurationStepEntity();
+
+ assertThrows(AccessDeniedException.class,
+ () ->
connectorResource.updateConnectorConfigurationStep(CONNECTOR_ID,
CONFIGURATION_STEP_NAME, requestEntity));
+
+ verify(lookup).getConnectorSecretProvider(SECRET_PROVIDER_ID, null,
null);
+ verify(serviceFacade,
never()).updateConnectorConfigurationStep(any(Revision.class), anyString(),
anyString(), any());
+ }
+
@Test
public void testGetFlow() {
final ProcessGroupFlowEntity responseEntity =
createProcessGroupFlowEntity();
diff --git
a/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/connectors/ConnectorAssetsIT.java
b/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/connectors/ConnectorAssetsIT.java
index e02a3b3e5b0..b509a571475 100644
---
a/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/connectors/ConnectorAssetsIT.java
+++
b/nifi-system-tests/nifi-system-test-suite/src/test/java/org/apache/nifi/tests/system/connectors/ConnectorAssetsIT.java
@@ -171,6 +171,7 @@ public class ConnectorAssetsIT extends NiFiSystemIT {
}
assertNotNull(groupWithoutAsset);
+ configuredAssetValue.setValueType(null);
configuredAssetValue.setAssetReferences(null);
final Map<String, ConnectorValueReferenceDTO>
propertyValuesWithoutAsset = groupWithoutAsset.getPropertyValues();
propertyValuesWithoutAsset.put(propertyName, configuredAssetValue);