This is an automated email from the ASF dual-hosted git repository.
turcsanyi 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 6bd480f6ce NIFI-15200 - Introduce Authentication Strategy for GCP
Credentials Controller Service
6bd480f6ce is described below
commit 6bd480f6cee4564516dcc3337156f3e38c019dc8
Author: Pierre Villard <[email protected]>
AuthorDate: Mon Nov 10 12:47:06 2025 +0100
NIFI-15200 - Introduce Authentication Strategy for GCP Credentials
Controller Service
This closes #10510.
Signed-off-by: Peter Turcsanyi <[email protected]>
---
.../factory/AuthenticationStrategy.java | 65 ++++++++++
.../factory/CredentialPropertyDescriptors.java | 36 +++---
.../credentials/factory/CredentialsFactory.java | 61 +++-------
.../credentials/factory/CredentialsStrategy.java | 19 ---
.../AbstractBooleanCredentialsStrategy.java | 69 -----------
.../strategies/AbstractCredentialsStrategy.java | 51 +-------
.../AbstractServiceAccountCredentialsStrategy.java | 4 +-
... => ApplicationDefaultCredentialsStrategy.java} | 15 +--
.../ComputeEngineCredentialsStrategy.java | 5 +-
...licitApplicationDefaultCredentialsStrategy.java | 46 -------
.../JsonFileServiceAccountCredentialsStrategy.java | 4 +-
...sonStringServiceAccountCredentialsStrategy.java | 4 +-
.../service/GCPCredentialsControllerService.java | 55 +++++++--
.../processors/gcp/bigquery/PutBigQueryIT.java | 4 +
.../factory/CredentialsFactoryTest.java | 24 ++--
.../factory/MockCredentialsFactoryProcessor.java | 17 +--
...PCredentialsControllerServiceMigrationTest.java | 133 +++++++++++++++++++++
.../service/GCPCredentialsServiceTest.java | 18 +--
18 files changed, 324 insertions(+), 306 deletions(-)
diff --git
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/AuthenticationStrategy.java
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/AuthenticationStrategy.java
new file mode 100644
index 0000000000..7dcaa2941e
--- /dev/null
+++
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/AuthenticationStrategy.java
@@ -0,0 +1,65 @@
+/*
+ * 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.processors.gcp.credentials.factory;
+
+import org.apache.nifi.components.DescribedValue;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+/**
+ * Supported authentication strategies for configuring GCP credentials.
+ */
+public enum AuthenticationStrategy implements DescribedValue {
+ APPLICATION_DEFAULT("Application Default Credentials", "Use Google
Application Default Credentials such as the GOOGLE_APPLICATION_CREDENTIALS
environment variable or gcloud configuration."),
+ SERVICE_ACCOUNT_JSON_FILE("Service Account Credentials (Json File)", "Use
a Service Account key stored in a JSON file."),
+ SERVICE_ACCOUNT_JSON("Service Account Credentials (Json Value)", "Use a
Service Account key provided directly as JSON."),
+ COMPUTE_ENGINE("Compute Engine Credentials", "Use the Compute Engine
service account available to the NiFi instance.");
+
+ private final String displayName;
+ private final String description;
+
+ AuthenticationStrategy(final String displayName, final String description)
{
+ this.displayName = displayName;
+ this.description = description;
+ }
+
+ @Override
+ public String getValue() {
+ return displayName;
+ }
+
+ @Override
+ public String getDisplayName() {
+ return displayName;
+ }
+
+ @Override
+ public String getDescription() {
+ return description;
+ }
+
+ public static Optional<AuthenticationStrategy> fromValue(final String
value) {
+ if (value == null) {
+ return Optional.empty();
+ }
+
+ return Arrays.stream(values())
+ .filter(strategy -> strategy.getValue().equals(value))
+ .findFirst();
+ }
+}
diff --git
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/CredentialPropertyDescriptors.java
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/CredentialPropertyDescriptors.java
index eadc9af773..6a87648f88 100644
---
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/CredentialPropertyDescriptors.java
+++
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/CredentialPropertyDescriptors.java
@@ -30,6 +30,14 @@ public final class CredentialPropertyDescriptors {
private CredentialPropertyDescriptors() { }
+ public static final PropertyDescriptor AUTHENTICATION_STRATEGY = new
PropertyDescriptor.Builder()
+ .name("Authentication Strategy")
+ .required(true)
+ .allowableValues(AuthenticationStrategy.class)
+
.defaultValue(AuthenticationStrategy.APPLICATION_DEFAULT.getValue())
+ .description("Specifies how NiFi authenticates to Google Cloud.
Depending on the strategy, additional properties might be required.")
+ .build();
+
/**
* Specifies use of Application Default Credentials
*
@@ -37,30 +45,12 @@ public final class CredentialPropertyDescriptors {
* Google Application Default Credentials
* </a>
*/
- public static final PropertyDescriptor USE_APPLICATION_DEFAULT_CREDENTIALS
= new PropertyDescriptor.Builder()
+ public static final PropertyDescriptor
LEGACY_USE_APPLICATION_DEFAULT_CREDENTIALS = new PropertyDescriptor.Builder()
.name("Use Application Default Credentials")
- .expressionLanguageSupported(ExpressionLanguageScope.NONE)
- .required(false)
- .addValidator(StandardValidators.BOOLEAN_VALIDATOR)
- .sensitive(false)
- .allowableValues("true", "false")
- .defaultValue("false")
- .description("If true, uses Google Application Default
Credentials, which checks the " +
- "GOOGLE_APPLICATION_CREDENTIALS environment variable for a
filepath to a service account JSON " +
- "key, the config generated by the gcloud sdk, the App
Engine service account, and the Compute" +
- " Engine service account.")
.build();
- public static final PropertyDescriptor USE_COMPUTE_ENGINE_CREDENTIALS =
new PropertyDescriptor.Builder()
+ public static final PropertyDescriptor
LEGACY_USE_COMPUTE_ENGINE_CREDENTIALS = new PropertyDescriptor.Builder()
.name("Use Compute Engine Credentials")
- .expressionLanguageSupported(ExpressionLanguageScope.NONE)
- .required(false)
- .addValidator(StandardValidators.BOOLEAN_VALIDATOR)
- .sensitive(false)
- .allowableValues("true", "false")
- .defaultValue("false")
- .description("If true, uses Google Compute Engine Credentials of
the Compute Engine VM Instance " +
- "which NiFi is running on.")
.build();
/**
@@ -73,16 +63,18 @@ public final class CredentialPropertyDescriptors {
public static final PropertyDescriptor SERVICE_ACCOUNT_JSON_FILE = new
PropertyDescriptor.Builder()
.name("Service Account JSON File")
.expressionLanguageSupported(ExpressionLanguageScope.NONE)
- .required(false)
+ .required(true)
.identifiesExternalResource(ResourceCardinality.SINGLE,
ResourceType.FILE)
+ .dependsOn(AUTHENTICATION_STRATEGY,
AuthenticationStrategy.SERVICE_ACCOUNT_JSON_FILE.getValue())
.description("Path to a file containing a Service Account key file
in JSON format.")
.build();
public static final PropertyDescriptor SERVICE_ACCOUNT_JSON = new
PropertyDescriptor.Builder()
.name("Service Account JSON")
.expressionLanguageSupported(ExpressionLanguageScope.ENVIRONMENT)
- .required(false)
+ .required(true)
.addValidator(JsonValidator.INSTANCE)
+ .dependsOn(AUTHENTICATION_STRATEGY,
AuthenticationStrategy.SERVICE_ACCOUNT_JSON.getValue())
.description("The raw JSON containing a Service Account keyfile.")
.sensitive(true)
.build();
diff --git
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/CredentialsFactory.java
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/CredentialsFactory.java
index 9aaf9c2774..fb186fea3d 100644
---
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/CredentialsFactory.java
+++
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/CredentialsFactory.java
@@ -19,19 +19,15 @@ package org.apache.nifi.processors.gcp.credentials.factory;
import com.google.auth.http.HttpTransportFactory;
import com.google.auth.oauth2.GoogleCredentials;
import org.apache.nifi.components.PropertyDescriptor;
-import org.apache.nifi.components.ValidationContext;
-import org.apache.nifi.components.ValidationResult;
+import
org.apache.nifi.processors.gcp.credentials.factory.strategies.ApplicationDefaultCredentialsStrategy;
import
org.apache.nifi.processors.gcp.credentials.factory.strategies.ComputeEngineCredentialsStrategy;
-import
org.apache.nifi.processors.gcp.credentials.factory.strategies.ExplicitApplicationDefaultCredentialsStrategy;
-import
org.apache.nifi.processors.gcp.credentials.factory.strategies.ImplicitApplicationDefaultCredentialsStrategy;
import
org.apache.nifi.processors.gcp.credentials.factory.strategies.JsonFileServiceAccountCredentialsStrategy;
import
org.apache.nifi.processors.gcp.credentials.factory.strategies.JsonStringServiceAccountCredentialsStrategy;
import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
+import java.util.EnumMap;
import java.util.Map;
+import java.util.Optional;
/**
* Generates GCP credentials in the form of GoogleCredential implementations
for processors
@@ -45,50 +41,20 @@ import java.util.Map;
*/
public class CredentialsFactory {
- private final List<CredentialsStrategy> strategies = new ArrayList<>();
+ private final Map<AuthenticationStrategy, CredentialsStrategy>
strategiesByAuthentication = new EnumMap<>(AuthenticationStrategy.class);
public CredentialsFactory() {
- // Primary Credential Strategies
- strategies.add(new ExplicitApplicationDefaultCredentialsStrategy());
- strategies.add(new JsonFileServiceAccountCredentialsStrategy());
- strategies.add(new JsonStringServiceAccountCredentialsStrategy());
- strategies.add(new ComputeEngineCredentialsStrategy());
-
- // Implicit Default is the catch-all primary strategy
- strategies.add(new ImplicitApplicationDefaultCredentialsStrategy());
+
strategiesByAuthentication.put(AuthenticationStrategy.APPLICATION_DEFAULT, new
ApplicationDefaultCredentialsStrategy());
+
strategiesByAuthentication.put(AuthenticationStrategy.SERVICE_ACCOUNT_JSON_FILE,
new JsonFileServiceAccountCredentialsStrategy());
+
strategiesByAuthentication.put(AuthenticationStrategy.SERVICE_ACCOUNT_JSON, new
JsonStringServiceAccountCredentialsStrategy());
+ strategiesByAuthentication.put(AuthenticationStrategy.COMPUTE_ENGINE,
new ComputeEngineCredentialsStrategy());
}
public CredentialsStrategy selectPrimaryStrategy(final
Map<PropertyDescriptor, String> properties) {
- for (CredentialsStrategy strategy : strategies) {
- if (strategy.canCreatePrimaryCredential(properties)) {
- return strategy;
- }
- }
- return null;
- }
-
- public CredentialsStrategy selectPrimaryStrategy(final ValidationContext
validationContext) {
- final Map<PropertyDescriptor, String> properties =
validationContext.getProperties();
- return selectPrimaryStrategy(properties);
- }
-
- /**
- * Validates GCP credential properties against the configured strategies
to report any validation errors.
- * @return Validation errors
- */
- public Collection<ValidationResult> validate(final ValidationContext
validationContext) {
- final CredentialsStrategy selectedStrategy =
selectPrimaryStrategy(validationContext);
- final List<ValidationResult> validationFailureResults = new
ArrayList<>();
-
- for (CredentialsStrategy strategy : strategies) {
- final Collection<ValidationResult> strategyValidationFailures =
strategy.validate(validationContext,
- selectedStrategy);
- if (strategyValidationFailures != null) {
- validationFailureResults.addAll(strategyValidationFailures);
- }
- }
-
- return validationFailureResults;
+ final String authenticationStrategyValue =
properties.get(CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY);
+ final Optional<AuthenticationStrategy> authenticationStrategy =
AuthenticationStrategy.fromValue(authenticationStrategyValue);
+ return authenticationStrategy.map(strategiesByAuthentication::get)
+
.orElse(strategiesByAuthentication.get(AuthenticationStrategy.APPLICATION_DEFAULT));
}
/**
@@ -100,6 +66,9 @@ public class CredentialsFactory {
*/
public GoogleCredentials getGoogleCredentials(final
Map<PropertyDescriptor, String> properties, final HttpTransportFactory
transportFactory) throws IOException {
final CredentialsStrategy primaryStrategy =
selectPrimaryStrategy(properties);
+ if (primaryStrategy == null) {
+ throw new IllegalStateException("No matching authentication
strategy is configured");
+ }
return primaryStrategy.getGoogleCredentials(properties,
transportFactory);
}
}
diff --git
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/CredentialsStrategy.java
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/CredentialsStrategy.java
index 1765e14ecb..63b780b50a 100644
---
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/CredentialsStrategy.java
+++
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/CredentialsStrategy.java
@@ -19,11 +19,8 @@ package org.apache.nifi.processors.gcp.credentials.factory;
import com.google.auth.http.HttpTransportFactory;
import com.google.auth.oauth2.GoogleCredentials;
import org.apache.nifi.components.PropertyDescriptor;
-import org.apache.nifi.components.ValidationContext;
-import org.apache.nifi.components.ValidationResult;
import java.io.IOException;
-import java.util.Collection;
import java.util.Map;
/**
@@ -39,22 +36,6 @@ public interface CredentialsStrategy {
*/
String getName();
- /**
- * Determines if this strategy can create primary credentials using the
given properties.
- * @return true if primary credentials can be created
- */
- boolean canCreatePrimaryCredential(Map<PropertyDescriptor, String>
properties);
-
-
- /**
- * Validates the properties belonging to this strategy, given the selected
primary strategy. Errors may result
- * from individually malformed properties, invalid combinations of
properties, or inappropriate use of properties
- * not consistent with the primary strategy.
- * @param primaryStrategy the prevailing primary strategy
- * @return validation errors
- */
- Collection<ValidationResult> validate(ValidationContext validationContext,
CredentialsStrategy primaryStrategy);
-
/**
* Creates an AuthCredentials instance for this strategy, given the
properties defined by the user.
* @param transportFactory Sub-classes should utilize this transport
factory
diff --git
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/AbstractBooleanCredentialsStrategy.java
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/AbstractBooleanCredentialsStrategy.java
deleted file mode 100644
index 7ed3eb33a6..0000000000
---
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/AbstractBooleanCredentialsStrategy.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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.processors.gcp.credentials.factory.strategies;
-
-import org.apache.nifi.components.PropertyDescriptor;
-import org.apache.nifi.components.ValidationContext;
-import org.apache.nifi.components.ValidationResult;
-import org.apache.nifi.processors.gcp.credentials.factory.CredentialsStrategy;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Map;
-
-
-/**
- * Partial implementation of CredentialsStrategy to provide support for
credential strategies specified by
- * a single boolean property.
- */
-public abstract class AbstractBooleanCredentialsStrategy extends
AbstractCredentialsStrategy {
-
- private PropertyDescriptor strategyProperty;
-
- public AbstractBooleanCredentialsStrategy(String name, PropertyDescriptor
strategyProperty) {
- super(name, new PropertyDescriptor[]{
- strategyProperty
- });
- this.strategyProperty = strategyProperty;
- }
-
- @Override
- public boolean canCreatePrimaryCredential(Map<PropertyDescriptor, String>
properties) {
- return (properties.get(this.strategyProperty) != null
- &&
properties.get(this.strategyProperty).equalsIgnoreCase("true"));
- }
-
- @Override
- public Collection<ValidationResult> validate(final ValidationContext
validationContext,
- final CredentialsStrategy
primaryStrategy) {
- boolean thisIsSelectedStrategy = this == primaryStrategy;
- Boolean useStrategy =
validationContext.getProperty(strategyProperty).asBoolean();
- if (!thisIsSelectedStrategy && (useStrategy == null ? false :
useStrategy)) {
- String failureFormat = "property %1$s cannot be used with %2$s";
- Collection<ValidationResult> validationFailureResults = new
ArrayList<>();
- String message = String.format(failureFormat,
strategyProperty.getDisplayName(),
- primaryStrategy.getName());
- validationFailureResults.add(new ValidationResult.Builder()
- .subject(strategyProperty.getDisplayName())
- .valid(false)
- .explanation(message).build());
- return validationFailureResults;
- }
- return null;
- }
-
-}
diff --git
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/AbstractCredentialsStrategy.java
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/AbstractCredentialsStrategy.java
index 44299dcc67..b80403e74e 100644
---
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/AbstractCredentialsStrategy.java
+++
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/AbstractCredentialsStrategy.java
@@ -16,65 +16,16 @@
*/
package org.apache.nifi.processors.gcp.credentials.factory.strategies;
-import org.apache.nifi.components.PropertyDescriptor;
-import org.apache.nifi.components.ValidationContext;
-import org.apache.nifi.components.ValidationResult;
import org.apache.nifi.processors.gcp.credentials.factory.CredentialsStrategy;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Map;
-
/**
* Partial implementation of CredentialsStrategy to support most simple
property-based strategies.
*/
public abstract class AbstractCredentialsStrategy implements
CredentialsStrategy {
private final String name;
- private final PropertyDescriptor[] requiredProperties;
- public AbstractCredentialsStrategy(String name, PropertyDescriptor[]
requiredProperties) {
+ public AbstractCredentialsStrategy(String name) {
this.name = name;
- this.requiredProperties = requiredProperties;
- }
-
- @Override
- public boolean canCreatePrimaryCredential(Map<PropertyDescriptor, String>
properties) {
- for (PropertyDescriptor requiredProperty : requiredProperties) {
- boolean containsRequiredProperty =
properties.containsKey(requiredProperty);
- String propertyValue = properties.get(requiredProperty);
- boolean containsValue = propertyValue != null;
- if (!containsRequiredProperty || !containsValue) {
- return false;
- }
- }
- return true;
- }
-
- @Override
- public Collection<ValidationResult> validate(final ValidationContext
validationContext,
- final CredentialsStrategy
primaryStrategy) {
- boolean thisIsSelectedStrategy = this == primaryStrategy;
- String requiredMessageFormat = "property %1$s must be set with %2$s";
- String excludedMessageFormat = "property %1$s cannot be used with
%2$s";
- String failureFormat = thisIsSelectedStrategy ? requiredMessageFormat
: excludedMessageFormat;
- Collection<ValidationResult> validationFailureResults = null;
-
- for (PropertyDescriptor requiredProperty : requiredProperties) {
- boolean requiredPropertyIsSet =
validationContext.getProperty(requiredProperty).isSet();
- if (requiredPropertyIsSet != thisIsSelectedStrategy) {
- String message = String.format(failureFormat,
requiredProperty.getDisplayName(),
- primaryStrategy.getName());
- if (validationFailureResults == null) {
- validationFailureResults = new ArrayList<>();
- }
- validationFailureResults.add(new ValidationResult.Builder()
- .subject(requiredProperty.getDisplayName())
- .valid(false)
- .explanation(message).build());
- }
- }
-
- return validationFailureResults;
}
@Override
diff --git
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/AbstractServiceAccountCredentialsStrategy.java
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/AbstractServiceAccountCredentialsStrategy.java
index 5bd3edbfcf..f8b6a9b8cc 100644
---
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/AbstractServiceAccountCredentialsStrategy.java
+++
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/AbstractServiceAccountCredentialsStrategy.java
@@ -31,8 +31,8 @@ import java.util.Map;
* or through a flat JSON file.
*/
public abstract class AbstractServiceAccountCredentialsStrategy extends
AbstractCredentialsStrategy {
- public AbstractServiceAccountCredentialsStrategy(String name,
PropertyDescriptor[] requiredProperties) {
- super(name, requiredProperties);
+ public AbstractServiceAccountCredentialsStrategy(String name) {
+ super(name);
}
protected abstract InputStream
getServiceAccountJson(Map<PropertyDescriptor, String> properties) throws
IOException;
diff --git
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/ImplicitApplicationDefaultCredentialsStrategy.java
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/ApplicationDefaultCredentialsStrategy.java
similarity index 71%
rename from
nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/ImplicitApplicationDefaultCredentialsStrategy.java
rename to
nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/ApplicationDefaultCredentialsStrategy.java
index e0535b0e5c..b51309ca1b 100644
---
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/ImplicitApplicationDefaultCredentialsStrategy.java
+++
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/ApplicationDefaultCredentialsStrategy.java
@@ -23,16 +23,17 @@ import org.apache.nifi.components.PropertyDescriptor;
import java.io.IOException;
import java.util.Map;
+
/**
- * Supports Google Cloud Application Default Credentials.
- * Compared to ExplicitApplicationDefaultCredentialsStrategy, this strategy is
always
- * willing to provide primary credentials, regardless of user input. It is
intended to be used as an invisible
- * fallback or default strategy.
+ * Supports GCP Application Default Credentials.
+ *
+ * @see <a
href="https://developers.google.com/identity/protocols/application-default-credentials">
+ * Application Default Credentials</a>
*/
-public class ImplicitApplicationDefaultCredentialsStrategy extends
AbstractCredentialsStrategy {
+public class ApplicationDefaultCredentialsStrategy extends
AbstractCredentialsStrategy {
- public ImplicitApplicationDefaultCredentialsStrategy() {
- super("Application Default Credentials", new PropertyDescriptor[]{});
+ public ApplicationDefaultCredentialsStrategy() {
+ super("Application Default Credentials");
}
@Override
diff --git
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/ComputeEngineCredentialsStrategy.java
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/ComputeEngineCredentialsStrategy.java
index e98fb33bf2..a1eefb0b68 100644
---
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/ComputeEngineCredentialsStrategy.java
+++
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/ComputeEngineCredentialsStrategy.java
@@ -20,7 +20,6 @@ import com.google.auth.http.HttpTransportFactory;
import com.google.auth.oauth2.ComputeEngineCredentials;
import com.google.auth.oauth2.GoogleCredentials;
import org.apache.nifi.components.PropertyDescriptor;
-import
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors;
import java.io.IOException;
import java.util.Map;
@@ -31,9 +30,9 @@ import java.util.Map;
* @see <a
href="https://cloud.google.com/compute/docs/access/create-enable-service-accounts-for-instances">
* Service Accounts for Instances</a>
*/
-public class ComputeEngineCredentialsStrategy extends
AbstractBooleanCredentialsStrategy {
+public class ComputeEngineCredentialsStrategy extends
AbstractCredentialsStrategy {
public ComputeEngineCredentialsStrategy() {
- super("Compute Engine Credentials",
CredentialPropertyDescriptors.USE_COMPUTE_ENGINE_CREDENTIALS);
+ super("Compute Engine Credentials");
}
@Override
diff --git
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/ExplicitApplicationDefaultCredentialsStrategy.java
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/ExplicitApplicationDefaultCredentialsStrategy.java
deleted file mode 100644
index 213d0b7f42..0000000000
---
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/ExplicitApplicationDefaultCredentialsStrategy.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * 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.processors.gcp.credentials.factory.strategies;
-
-import com.google.auth.http.HttpTransportFactory;
-import com.google.auth.oauth2.GoogleCredentials;
-import org.apache.nifi.components.PropertyDescriptor;
-import
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors;
-
-import java.io.IOException;
-import java.util.Map;
-
-
-/**
- * Supports GCP Application Default Credentials. Compared to
ImplicitApplicationDefaultCredentialsStrategy, this
- * strategy is designed to be visible to the user, and depends on an
affirmative selection from the user.
- *
- * @see <a
href="https://developers.google.com/identity/protocols/application-default-credentials">
- * Application Default Credentials</a>
- */
-public class ExplicitApplicationDefaultCredentialsStrategy extends
AbstractBooleanCredentialsStrategy {
-
- public ExplicitApplicationDefaultCredentialsStrategy() {
- super("Application Default Credentials",
CredentialPropertyDescriptors.USE_APPLICATION_DEFAULT_CREDENTIALS);
- }
-
- @Override
- public GoogleCredentials getGoogleCredentials(Map<PropertyDescriptor,
String> properties, HttpTransportFactory transportFactory) throws IOException {
- return GoogleCredentials.getApplicationDefault(transportFactory);
- }
-
-}
diff --git
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/JsonFileServiceAccountCredentialsStrategy.java
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/JsonFileServiceAccountCredentialsStrategy.java
index 924a2ae22b..b05d1ea6fa 100644
---
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/JsonFileServiceAccountCredentialsStrategy.java
+++
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/JsonFileServiceAccountCredentialsStrategy.java
@@ -36,9 +36,7 @@ import java.util.Map;
public class JsonFileServiceAccountCredentialsStrategy extends
AbstractServiceAccountCredentialsStrategy {
public JsonFileServiceAccountCredentialsStrategy() {
- super("Service Account Credentials (Json File)", new
PropertyDescriptor[] {
- CredentialPropertyDescriptors.SERVICE_ACCOUNT_JSON_FILE
- });
+ super("Service Account Credentials (Json File)");
}
@Override
diff --git
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/JsonStringServiceAccountCredentialsStrategy.java
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/JsonStringServiceAccountCredentialsStrategy.java
index 3a40a7878f..f334d27298 100644
---
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/JsonStringServiceAccountCredentialsStrategy.java
+++
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/factory/strategies/JsonStringServiceAccountCredentialsStrategy.java
@@ -33,9 +33,7 @@ import java.util.Map;
public class JsonStringServiceAccountCredentialsStrategy extends
AbstractServiceAccountCredentialsStrategy {
public JsonStringServiceAccountCredentialsStrategy() {
- super("Service Account Credentials (Json String)", new
PropertyDescriptor[] {
- CredentialPropertyDescriptors.SERVICE_ACCOUNT_JSON
- });
+ super("Service Account Credentials (Json String)");
}
@Override
diff --git
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/service/GCPCredentialsControllerService.java
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/service/GCPCredentialsControllerService.java
index fdaf38fd5c..5a2227112a 100644
---
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/service/GCPCredentialsControllerService.java
+++
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/main/java/org/apache/nifi/processors/gcp/credentials/service/GCPCredentialsControllerService.java
@@ -37,22 +37,26 @@ import org.apache.nifi.logging.ComponentLog;
import org.apache.nifi.migration.PropertyConfiguration;
import org.apache.nifi.processor.exception.ProcessException;
import org.apache.nifi.processors.gcp.ProxyAwareTransportFactory;
+import
org.apache.nifi.processors.gcp.credentials.factory.AuthenticationStrategy;
import org.apache.nifi.processors.gcp.credentials.factory.CredentialsFactory;
import org.apache.nifi.proxy.ProxyConfiguration;
import org.apache.nifi.reporting.InitializationException;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.Optional;
+import static
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY;
import static
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors.DELEGATION_STRATEGY;
import static
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors.DELEGATION_USER;
+import static
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors.LEGACY_USE_APPLICATION_DEFAULT_CREDENTIALS;
+import static
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors.LEGACY_USE_COMPUTE_ENGINE_CREDENTIALS;
import static
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors.SERVICE_ACCOUNT_JSON;
import static
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors.SERVICE_ACCOUNT_JSON_FILE;
-import static
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors.USE_APPLICATION_DEFAULT_CREDENTIALS;
-import static
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors.USE_COMPUTE_ENGINE_CREDENTIALS;
/**
* Implementation of GCPCredentialsService interface
@@ -76,8 +80,7 @@ import static
org.apache.nifi.processors.gcp.credentials.factory.CredentialPrope
public class GCPCredentialsControllerService extends AbstractControllerService
implements GCPCredentialsService, VerifiableControllerService {
private static final List<PropertyDescriptor> PROPERTY_DESCRIPTORS =
List.of(
- USE_APPLICATION_DEFAULT_CREDENTIALS,
- USE_COMPUTE_ENGINE_CREDENTIALS,
+ AUTHENTICATION_STRATEGY,
SERVICE_ACCOUNT_JSON_FILE,
SERVICE_ACCOUNT_JSON,
ProxyConfiguration.createProxyConfigPropertyDescriptor(ProxyAwareTransportFactory.PROXY_SPECS),
@@ -100,7 +103,7 @@ public class GCPCredentialsControllerService extends
AbstractControllerService i
@Override
protected Collection<ValidationResult> customValidate(final
ValidationContext validationContext) {
- final Collection<ValidationResult> results =
credentialsProviderFactory.validate(validationContext);
+ final Collection<ValidationResult> results = new ArrayList<>();
ProxyConfiguration.validateProxySpec(validationContext, results,
ProxyAwareTransportFactory.PROXY_SPECS);
return results;
}
@@ -136,10 +139,46 @@ public class GCPCredentialsControllerService extends
AbstractControllerService i
@Override
public void migrateProperties(PropertyConfiguration config) {
- config.renameProperty("application-default-credentials",
USE_APPLICATION_DEFAULT_CREDENTIALS.getName());
- config.renameProperty("compute-engine-credentials",
USE_COMPUTE_ENGINE_CREDENTIALS.getName());
+ config.renameProperty("application-default-credentials",
LEGACY_USE_APPLICATION_DEFAULT_CREDENTIALS.getName());
+ config.renameProperty("compute-engine-credentials",
LEGACY_USE_COMPUTE_ENGINE_CREDENTIALS.getName());
config.renameProperty("service-account-json-file",
SERVICE_ACCOUNT_JSON_FILE.getName());
config.renameProperty("service-account-json",
SERVICE_ACCOUNT_JSON.getName());
+
+ final boolean legacyFlagsPresent =
config.hasProperty(LEGACY_USE_APPLICATION_DEFAULT_CREDENTIALS)
+ || config.hasProperty(LEGACY_USE_COMPUTE_ENGINE_CREDENTIALS);
+ final Optional<String> authenticationStrategyValue =
config.getRawPropertyValue(AUTHENTICATION_STRATEGY)
+ .map(String::trim)
+ .filter(value -> !value.isEmpty());
+ final boolean authenticationStrategyMissing =
authenticationStrategyValue.isEmpty();
+
+ if (authenticationStrategyMissing || legacyFlagsPresent) {
+ final AuthenticationStrategy authenticationStrategy =
determineAuthenticationStrategy(config);
+ if (authenticationStrategy != null) {
+ config.setProperty(AUTHENTICATION_STRATEGY,
authenticationStrategy.getValue());
+ }
+ }
+
+
config.removeProperty(LEGACY_USE_APPLICATION_DEFAULT_CREDENTIALS.getName());
+ config.removeProperty(LEGACY_USE_COMPUTE_ENGINE_CREDENTIALS.getName());
+ }
+
+ private AuthenticationStrategy determineAuthenticationStrategy(final
PropertyConfiguration config) {
+ if (isTrue(config, LEGACY_USE_APPLICATION_DEFAULT_CREDENTIALS)) {
+ return AuthenticationStrategy.APPLICATION_DEFAULT;
+ } else if (config.isPropertySet(SERVICE_ACCOUNT_JSON_FILE)) {
+ return AuthenticationStrategy.SERVICE_ACCOUNT_JSON_FILE;
+ } else if (config.isPropertySet(SERVICE_ACCOUNT_JSON)) {
+ return AuthenticationStrategy.SERVICE_ACCOUNT_JSON;
+ } else if (isTrue(config, LEGACY_USE_COMPUTE_ENGINE_CREDENTIALS)) {
+ return AuthenticationStrategy.COMPUTE_ENGINE;
+ }
+ return AuthenticationStrategy.APPLICATION_DEFAULT;
+ }
+
+ private boolean isTrue(final PropertyConfiguration config, final
PropertyDescriptor property) {
+ return config.getRawPropertyValue(property)
+ .map(value -> "true".equalsIgnoreCase(value.trim()))
+ .orElse(false);
}
private GoogleCredentials getGoogleCredentials(final ConfigurationContext
context) throws IOException {
@@ -152,4 +191,4 @@ public class GCPCredentialsControllerService extends
AbstractControllerService i
public String toString() {
return "GCPCredentialsControllerService[id=" + getIdentifier() + "]";
}
-}
\ No newline at end of file
+}
diff --git
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/test/java/org/apache/nifi/processors/gcp/bigquery/PutBigQueryIT.java
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/test/java/org/apache/nifi/processors/gcp/bigquery/PutBigQueryIT.java
index c0c0f6354f..f503a3b732 100644
---
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/test/java/org/apache/nifi/processors/gcp/bigquery/PutBigQueryIT.java
+++
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/test/java/org/apache/nifi/processors/gcp/bigquery/PutBigQueryIT.java
@@ -67,6 +67,8 @@ import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import
org.apache.nifi.processors.gcp.credentials.factory.AuthenticationStrategy;
+
import static
org.apache.nifi.processors.gcp.bigquery.AbstractBigQueryProcessor.DATASET;
import static
org.apache.nifi.processors.gcp.bigquery.AbstractBigQueryProcessor.TABLE_NAME;
import static
org.apache.nifi.processors.gcp.bigquery.PutBigQuery.RECORD_READER;
@@ -96,6 +98,7 @@ public class PutBigQueryIT {
@BeforeAll
public static void beforeClass() throws IOException {
final Map<PropertyDescriptor, String> propertiesMap = new HashMap<>();
+
propertiesMap.put(CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY,
AuthenticationStrategy.SERVICE_ACCOUNT_JSON_FILE.getValue());
propertiesMap.put(CredentialPropertyDescriptors.SERVICE_ACCOUNT_JSON_FILE,
SERVICE_ACCOUNT_JSON);
Credentials credentials =
credentialsProviderFactory.getGoogleCredentials(propertiesMap, new
ProxyAwareTransportFactory(null));
@@ -120,6 +123,7 @@ public class PutBigQueryIT {
final GCPCredentialsControllerService credentialsControllerService =
new GCPCredentialsControllerService();
final Map<String, String> propertiesMap = new HashMap<>();
+
propertiesMap.put(CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY.getName(),
AuthenticationStrategy.SERVICE_ACCOUNT_JSON_FILE.getValue());
propertiesMap.put(CredentialPropertyDescriptors.SERVICE_ACCOUNT_JSON_FILE.getName(),
SERVICE_ACCOUNT_JSON);
runner.addControllerService(CONTROLLER_SERVICE,
credentialsControllerService, propertiesMap);
diff --git
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/test/java/org/apache/nifi/processors/gcp/credentials/factory/CredentialsFactoryTest.java
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/test/java/org/apache/nifi/processors/gcp/credentials/factory/CredentialsFactoryTest.java
index d2107d1b12..ac1fcf7597 100644
---
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/test/java/org/apache/nifi/processors/gcp/credentials/factory/CredentialsFactoryTest.java
+++
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/test/java/org/apache/nifi/processors/gcp/credentials/factory/CredentialsFactoryTest.java
@@ -38,7 +38,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
/**
- * Tests of the validation and credentials provider capabilities of
CredentialsFactory.
+ * Tests of the credentials provider capabilities of CredentialsFactory.
*/
public class CredentialsFactoryTest {
@@ -68,7 +68,7 @@ public class CredentialsFactoryTest {
@Test
public void testExplicitApplicationDefaultCredentials() throws Exception {
final TestRunner runner =
TestRunners.newTestRunner(MockCredentialsFactoryProcessor.class);
-
runner.setProperty(CredentialPropertyDescriptors.USE_APPLICATION_DEFAULT_CREDENTIALS,
"true");
+
runner.setProperty(CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY,
AuthenticationStrategy.APPLICATION_DEFAULT.getValue());
runner.assertValid();
Map<PropertyDescriptor, String> properties =
runner.getProcessContext().getProperties();
@@ -79,16 +79,24 @@ public class CredentialsFactoryTest {
}
@Test
- public void testExplicitApplicationDefaultCredentialsExclusive() throws
Exception {
+ public void
testExplicitApplicationDefaultCredentialsIgnoresServiceAccountFile() throws
Exception {
final TestRunner runner =
TestRunners.newTestRunner(MockCredentialsFactoryProcessor.class);
-
runner.setProperty(CredentialPropertyDescriptors.USE_APPLICATION_DEFAULT_CREDENTIALS,
"true");
-
runner.setProperty(CredentialPropertyDescriptors.USE_COMPUTE_ENGINE_CREDENTIALS,
"true");
- runner.assertNotValid();
+
runner.setProperty(CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY,
AuthenticationStrategy.APPLICATION_DEFAULT.getValue());
+
runner.setProperty(CredentialPropertyDescriptors.SERVICE_ACCOUNT_JSON_FILE,
+ "src/test/resources/mock-gcp-service-account.json");
+ runner.assertValid();
+
+ final Map<PropertyDescriptor, String> properties =
runner.getProcessContext().getProperties();
+ final CredentialsFactory factory = new CredentialsFactory();
+ final GoogleCredentials credentials =
factory.getGoogleCredentials(properties, TRANSPORT_FACTORY);
+
+ assertNotNull(credentials);
}
@Test
public void testJsonFileCredentials() throws Exception {
final TestRunner runner =
TestRunners.newTestRunner(MockCredentialsFactoryProcessor.class);
+
runner.setProperty(CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY,
AuthenticationStrategy.SERVICE_ACCOUNT_JSON_FILE.getValue());
runner.setProperty(CredentialPropertyDescriptors.SERVICE_ACCOUNT_JSON_FILE,
"src/test/resources/mock-gcp-service-account.json");
runner.assertValid();
@@ -106,6 +114,7 @@ public class CredentialsFactoryTest {
@Test
public void testBadJsonFileCredentials() throws Exception {
final TestRunner runner =
TestRunners.newTestRunner(MockCredentialsFactoryProcessor.class);
+
runner.setProperty(CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY,
AuthenticationStrategy.SERVICE_ACCOUNT_JSON_FILE.getValue());
runner.setProperty(CredentialPropertyDescriptors.SERVICE_ACCOUNT_JSON_FILE,
"src/test/resources/bad-mock-gcp-service-account.json");
runner.assertNotValid();
@@ -117,6 +126,7 @@ public class CredentialsFactoryTest {
Files.readAllBytes(Paths.get("src/test/resources/mock-gcp-service-account.json"))
);
final TestRunner runner =
TestRunners.newTestRunner(MockCredentialsFactoryProcessor.class);
+
runner.setProperty(CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY,
AuthenticationStrategy.SERVICE_ACCOUNT_JSON.getValue());
runner.setProperty(CredentialPropertyDescriptors.SERVICE_ACCOUNT_JSON,
jsonRead);
runner.assertValid();
@@ -133,7 +143,7 @@ public class CredentialsFactoryTest {
@Test
public void testComputeEngineCredentials() throws Exception {
final TestRunner runner =
TestRunners.newTestRunner(MockCredentialsFactoryProcessor.class);
-
runner.setProperty(CredentialPropertyDescriptors.USE_COMPUTE_ENGINE_CREDENTIALS,
"true");
+
runner.setProperty(CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY,
AuthenticationStrategy.COMPUTE_ENGINE.getValue());
runner.assertValid();
Map<PropertyDescriptor, String> properties =
runner.getProcessContext().getProperties();
diff --git
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/test/java/org/apache/nifi/processors/gcp/credentials/factory/MockCredentialsFactoryProcessor.java
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/test/java/org/apache/nifi/processors/gcp/credentials/factory/MockCredentialsFactoryProcessor.java
index 84614e961e..b57863b917 100644
---
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/test/java/org/apache/nifi/processors/gcp/credentials/factory/MockCredentialsFactoryProcessor.java
+++
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/test/java/org/apache/nifi/processors/gcp/credentials/factory/MockCredentialsFactoryProcessor.java
@@ -20,31 +20,26 @@ import com.google.auth.oauth2.GoogleCredentials;
import com.google.cloud.Service;
import com.google.cloud.ServiceOptions;
import org.apache.nifi.components.PropertyDescriptor;
-import org.apache.nifi.components.ValidationContext;
-import org.apache.nifi.components.ValidationResult;
import org.apache.nifi.processor.ProcessContext;
import org.apache.nifi.processor.ProcessSession;
import org.apache.nifi.processor.exception.ProcessException;
import org.apache.nifi.processors.gcp.AbstractGCPProcessor;
import java.util.Arrays;
-import java.util.Collection;
import java.util.List;
+import static
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY;
import static
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors.SERVICE_ACCOUNT_JSON;
import static
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors.SERVICE_ACCOUNT_JSON_FILE;
-import static
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors.USE_APPLICATION_DEFAULT_CREDENTIALS;
-import static
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors.USE_COMPUTE_ENGINE_CREDENTIALS;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class MockCredentialsFactoryProcessor extends AbstractGCPProcessor {
public final List<PropertyDescriptor> properties = Arrays.asList(
- USE_APPLICATION_DEFAULT_CREDENTIALS,
+ AUTHENTICATION_STRATEGY,
SERVICE_ACCOUNT_JSON,
- SERVICE_ACCOUNT_JSON_FILE,
- USE_COMPUTE_ENGINE_CREDENTIALS
+ SERVICE_ACCOUNT_JSON_FILE
);
@Override
@@ -65,10 +60,4 @@ public class MockCredentialsFactoryProcessor extends
AbstractGCPProcessor {
public void onTrigger(ProcessContext context, ProcessSession session)
throws ProcessException {
}
-
- @Override
- protected Collection<ValidationResult> customValidate(ValidationContext
validationContext) {
- CredentialsFactory factory = new CredentialsFactory();
- return factory.validate(validationContext);
- }
}
diff --git
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/test/java/org/apache/nifi/processors/gcp/credentials/service/GCPCredentialsControllerServiceMigrationTest.java
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/test/java/org/apache/nifi/processors/gcp/credentials/service/GCPCredentialsControllerServiceMigrationTest.java
new file mode 100644
index 0000000000..6a71c1995e
--- /dev/null
+++
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/test/java/org/apache/nifi/processors/gcp/credentials/service/GCPCredentialsControllerServiceMigrationTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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.processors.gcp.credentials.service;
+
+import
org.apache.nifi.processors.gcp.credentials.factory.AuthenticationStrategy;
+import
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors;
+import org.apache.nifi.util.MockPropertyConfiguration;
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+
+class GCPCredentialsControllerServiceMigrationTest {
+
+ private static final String SERVICE_ACCOUNT_JSON_PLACEHOLDER =
"{\"mock\":\"json\"}";
+ private final GCPCredentialsControllerService service = new
GCPCredentialsControllerService();
+
+ @Test
+ void testMigratesApplicationDefaultFlag() {
+ final Map<String, String> properties = new HashMap<>();
+
properties.put(CredentialPropertyDescriptors.LEGACY_USE_APPLICATION_DEFAULT_CREDENTIALS.getName(),
"true");
+
+ final MockPropertyConfiguration configuration = new
MockPropertyConfiguration(properties);
+ service.migrateProperties(configuration);
+
+ assertEquals(AuthenticationStrategy.APPLICATION_DEFAULT.getValue(),
+
configuration.getRawProperties().get(CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY.getName()));
+
assertFalse(configuration.getRawProperties().containsKey(CredentialPropertyDescriptors.LEGACY_USE_APPLICATION_DEFAULT_CREDENTIALS.getName()));
+ }
+
+ @Test
+ void testMigratesServiceAccountFile() {
+ final Map<String, String> properties = new HashMap<>();
+
properties.put(CredentialPropertyDescriptors.SERVICE_ACCOUNT_JSON_FILE.getName(),
"/tmp/account.json");
+
+ final MockPropertyConfiguration configuration = new
MockPropertyConfiguration(properties);
+ service.migrateProperties(configuration);
+
+
assertEquals(AuthenticationStrategy.SERVICE_ACCOUNT_JSON_FILE.getValue(),
+
configuration.getRawProperties().get(CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY.getName()));
+ }
+
+ @Test
+ void testMigratesServiceAccountJson() {
+ final Map<String, String> properties = new HashMap<>();
+
properties.put(CredentialPropertyDescriptors.SERVICE_ACCOUNT_JSON.getName(),
SERVICE_ACCOUNT_JSON_PLACEHOLDER);
+
+ final MockPropertyConfiguration configuration = new
MockPropertyConfiguration(properties);
+ service.migrateProperties(configuration);
+
+ assertEquals(AuthenticationStrategy.SERVICE_ACCOUNT_JSON.getValue(),
+
configuration.getRawProperties().get(CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY.getName()));
+ }
+
+ @Test
+ void testMigratesComputeEngineFlag() {
+ final Map<String, String> properties = new HashMap<>();
+
properties.put(CredentialPropertyDescriptors.LEGACY_USE_COMPUTE_ENGINE_CREDENTIALS.getName(),
"true");
+
+ final MockPropertyConfiguration configuration = new
MockPropertyConfiguration(properties);
+ service.migrateProperties(configuration);
+
+ assertEquals(AuthenticationStrategy.COMPUTE_ENGINE.getValue(),
+
configuration.getRawProperties().get(CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY.getName()));
+
assertFalse(configuration.getRawProperties().containsKey(CredentialPropertyDescriptors.LEGACY_USE_COMPUTE_ENGINE_CREDENTIALS.getName()));
+ }
+
+ @Test
+ void testDoesNotOverrideExistingAuthenticationStrategy() {
+ final Map<String, String> properties = new HashMap<>();
+
properties.put(CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY.getName(),
AuthenticationStrategy.SERVICE_ACCOUNT_JSON.getValue());
+
properties.put(CredentialPropertyDescriptors.SERVICE_ACCOUNT_JSON_FILE.getName(),
"/tmp/account.json");
+
+ final MockPropertyConfiguration configuration = new
MockPropertyConfiguration(properties);
+ service.migrateProperties(configuration);
+
+ assertEquals(AuthenticationStrategy.SERVICE_ACCOUNT_JSON.getValue(),
+
configuration.getRawProperties().get(CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY.getName()));
+ }
+
+ @Test
+ void testSetsDefaultAuthenticationStrategyWhenUnset() {
+ final Map<String, String> properties = new HashMap<>();
+ final MockPropertyConfiguration configuration = new
MockPropertyConfiguration(properties);
+
+ service.migrateProperties(configuration);
+
+ assertEquals(AuthenticationStrategy.APPLICATION_DEFAULT.getValue(),
+
configuration.getRawProperties().get(CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY.getName()));
+ }
+
+ @Test
+ void testLegacyPropertiesDeriveAuthenticationStrategyWhenMissing() {
+ final Map<String, String> properties = new HashMap<>();
+
properties.put(CredentialPropertyDescriptors.SERVICE_ACCOUNT_JSON_FILE.getName(),
"/tmp/account.json");
+
+ final MockPropertyConfiguration configuration = new
MockPropertyConfiguration(properties);
+ service.migrateProperties(configuration);
+
+
assertEquals(AuthenticationStrategy.SERVICE_ACCOUNT_JSON_FILE.getValue(),
+
configuration.getRawProperties().get(CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY.getName()));
+ }
+
+ @Test
+ void testDoesNotOverrideExplicitStrategyWhenServiceAccountPropertiesSet() {
+ final Map<String, String> properties = new HashMap<>();
+
properties.put(CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY.getName(),
AuthenticationStrategy.APPLICATION_DEFAULT.getValue());
+
properties.put(CredentialPropertyDescriptors.SERVICE_ACCOUNT_JSON_FILE.getName(),
"/tmp/account.json");
+
+ final MockPropertyConfiguration configuration = new
MockPropertyConfiguration(properties);
+ service.migrateProperties(configuration);
+
+ assertEquals(AuthenticationStrategy.APPLICATION_DEFAULT.getValue(),
+
configuration.getRawProperties().get(CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY.getName()));
+ }
+}
diff --git
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/test/java/org/apache/nifi/processors/gcp/credentials/service/GCPCredentialsServiceTest.java
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/test/java/org/apache/nifi/processors/gcp/credentials/service/GCPCredentialsServiceTest.java
index 95ed29fe8a..ab04129260 100644
---
a/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/test/java/org/apache/nifi/processors/gcp/credentials/service/GCPCredentialsServiceTest.java
+++
b/nifi-extension-bundles/nifi-gcp-bundle/nifi-gcp-processors/src/test/java/org/apache/nifi/processors/gcp/credentials/service/GCPCredentialsServiceTest.java
@@ -19,6 +19,7 @@ package org.apache.nifi.processors.gcp.credentials.service;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.auth.oauth2.ServiceAccountCredentials;
import org.apache.nifi.gcp.credentials.service.GCPCredentialsService;
+import
org.apache.nifi.processors.gcp.credentials.factory.AuthenticationStrategy;
import org.apache.nifi.util.TestRunner;
import org.apache.nifi.util.TestRunners;
import org.junit.jupiter.api.Test;
@@ -26,10 +27,9 @@ import org.junit.jupiter.api.Test;
import java.nio.file.Files;
import java.nio.file.Paths;
+import static
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors.AUTHENTICATION_STRATEGY;
import static
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors.SERVICE_ACCOUNT_JSON;
import static
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors.SERVICE_ACCOUNT_JSON_FILE;
-import static
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors.USE_APPLICATION_DEFAULT_CREDENTIALS;
-import static
org.apache.nifi.processors.gcp.credentials.factory.CredentialPropertyDescriptors.USE_COMPUTE_ENGINE_CREDENTIALS;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -66,7 +66,7 @@ public class GCPCredentialsServiceTest {
final GCPCredentialsControllerService serviceImpl = new
GCPCredentialsControllerService();
runner.addControllerService("gcpCredentialsProvider", serviceImpl);
- runner.setProperty(serviceImpl, USE_APPLICATION_DEFAULT_CREDENTIALS,
"true");
+ runner.setProperty(serviceImpl, AUTHENTICATION_STRATEGY,
AuthenticationStrategy.APPLICATION_DEFAULT.getValue());
runner.enableControllerService(serviceImpl);
runner.assertValid(serviceImpl);
@@ -85,6 +85,7 @@ public class GCPCredentialsServiceTest {
final GCPCredentialsControllerService serviceImpl = new
GCPCredentialsControllerService();
runner.addControllerService("gcpCredentialsProvider", serviceImpl);
+ runner.setProperty(serviceImpl, AUTHENTICATION_STRATEGY,
AuthenticationStrategy.SERVICE_ACCOUNT_JSON_FILE.getValue());
runner.setProperty(serviceImpl, SERVICE_ACCOUNT_JSON_FILE,
"src/test/resources/mock-gcp-service-account.json");
runner.enableControllerService(serviceImpl);
@@ -107,23 +108,25 @@ public class GCPCredentialsServiceTest {
final TestRunner runner =
TestRunners.newTestRunner(MockCredentialsServiceProcessor.class);
final GCPCredentialsControllerService serviceImpl = new
GCPCredentialsControllerService();
runner.addControllerService("gcpCredentialsProvider", serviceImpl);
+ runner.setProperty(serviceImpl, AUTHENTICATION_STRATEGY,
AuthenticationStrategy.SERVICE_ACCOUNT_JSON_FILE.getValue());
runner.setProperty(serviceImpl, SERVICE_ACCOUNT_JSON_FILE,
"src/test/resources/bad-mock-gcp-service-account.json");
runner.assertNotValid(serviceImpl);
}
@Test
- public void testMultipleCredentialSources() throws Exception {
+ public void testMultipleCredentialSourcesRemainValid() throws Exception {
final TestRunner runner =
TestRunners.newTestRunner(MockCredentialsServiceProcessor.class);
final GCPCredentialsControllerService serviceImpl = new
GCPCredentialsControllerService();
runner.addControllerService("gcpCredentialsProvider", serviceImpl);
+ runner.setProperty(serviceImpl, AUTHENTICATION_STRATEGY,
AuthenticationStrategy.SERVICE_ACCOUNT_JSON_FILE.getValue());
runner.setProperty(serviceImpl, SERVICE_ACCOUNT_JSON_FILE,
"src/test/resources/mock-gcp-service-account.json");
- runner.setProperty(serviceImpl, USE_APPLICATION_DEFAULT_CREDENTIALS,
"true");
- runner.setProperty(serviceImpl, USE_COMPUTE_ENGINE_CREDENTIALS,
"true");
+ runner.setProperty(serviceImpl, SERVICE_ACCOUNT_JSON,
+ "{\"mock\":\"json\"}");
- runner.assertNotValid(serviceImpl);
+ runner.assertValid(serviceImpl);
}
@Test
@@ -136,6 +139,7 @@ public class GCPCredentialsServiceTest {
final GCPCredentialsControllerService serviceImpl = new
GCPCredentialsControllerService();
runner.addControllerService("gcpCredentialsProvider", serviceImpl);
+ runner.setProperty(serviceImpl, AUTHENTICATION_STRATEGY,
AuthenticationStrategy.SERVICE_ACCOUNT_JSON.getValue());
runner.setProperty(serviceImpl, SERVICE_ACCOUNT_JSON,
jsonRead);
runner.enableControllerService(serviceImpl);