Repository: nifi
Updated Branches:
  refs/heads/master 4dd50c80a -> 9bb6dcb5e


NIFI-786 AWS credential refactoring and enhancements

Signed-off-by: Joe Skora <jsk...@gmail.com>
This closes #244.


Project: http://git-wip-us.apache.org/repos/asf/nifi/repo
Commit: http://git-wip-us.apache.org/repos/asf/nifi/commit/9bb6dcb5
Tree: http://git-wip-us.apache.org/repos/asf/nifi/tree/9bb6dcb5
Diff: http://git-wip-us.apache.org/repos/asf/nifi/diff/9bb6dcb5

Branch: refs/heads/master
Commit: 9bb6dcb5e58e3557a8545b97fa9ceef26124903c
Parents: 4dd50c8
Author: James Wing <jvw...@gmail.com>
Authored: Mon Feb 22 10:14:47 2016 -0800
Committer: Joe Skora <jsk...@gmail.com>
Committed: Tue May 24 00:27:13 2016 -0400

----------------------------------------------------------------------
 .../processors/aws/AbstractAWSProcessor.java    |  26 +--
 .../factory/CredentialPropertyDescriptors.java  | 158 +++++++++++++++
 .../factory/CredentialsProviderFactory.java     | 125 ++++++++++++
 .../provider/factory/CredentialsStrategy.java   |  75 +++++++
 .../AbstractBooleanCredentialsStrategy.java     |  70 +++++++
 .../strategies/AbstractCredentialsStrategy.java | 101 ++++++++++
 .../AccessKeyPairCredentialsStrategy.java       |  52 +++++
 .../AnonymousCredentialsStrategy.java           |  47 +++++
 .../AssumeRoleCredentialsStrategy.java          | 128 ++++++++++++
 .../ExplicitDefaultCredentialsStrategy.java     |  46 +++++
 .../strategies/FileCredentialsStrategy.java     |  53 +++++
 .../ImplicitDefaultCredentialsStrategy.java     |  43 ++++
 .../NamedProfileCredentialsStrategy.java        |  48 +++++
 ...AWSCredentialsProviderControllerService.java | 137 +++----------
 .../provider/factory/MockAWSProcessor.java      | 104 ++++++++++
 .../factory/TestCredentialsProviderFactory.java | 201 +++++++++++++++++++
 16 files changed, 1283 insertions(+), 131 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/nifi/blob/9bb6dcb5/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/AbstractAWSProcessor.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/AbstractAWSProcessor.java
 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/AbstractAWSProcessor.java
index e2c2196..3d4e458 100644
--- 
a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/AbstractAWSProcessor.java
+++ 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/AbstractAWSProcessor.java
@@ -41,6 +41,7 @@ import org.apache.nifi.processor.ProcessContext;
 import org.apache.nifi.processor.Relationship;
 import org.apache.nifi.processor.exception.ProcessException;
 import org.apache.nifi.processor.util.StandardValidators;
+import 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors;
 import org.apache.nifi.ssl.SSLContextService;
 
 import com.amazonaws.AmazonWebServiceClient;
@@ -72,28 +73,9 @@ public abstract class AbstractAWSProcessor<ClientType 
extends AmazonWebServiceCl
     public static final Set<Relationship> relationships = 
Collections.unmodifiableSet(
             new HashSet<>(Arrays.asList(REL_SUCCESS, REL_FAILURE)));
 
-    public static final PropertyDescriptor CREDENTIALS_FILE = new 
PropertyDescriptor.Builder()
-            .name("Credentials File")
-            .expressionLanguageSupported(false)
-            .required(false)
-            .addValidator(StandardValidators.FILE_EXISTS_VALIDATOR)
-            .build();
-
-    public static final PropertyDescriptor ACCESS_KEY = new 
PropertyDescriptor.Builder()
-            .name("Access Key")
-            .expressionLanguageSupported(true)
-            .required(false)
-            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
-            .sensitive(true)
-            .build();
-
-    public static final PropertyDescriptor SECRET_KEY = new 
PropertyDescriptor.Builder()
-            .name("Secret Key")
-            .expressionLanguageSupported(true)
-            .required(false)
-            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
-            .sensitive(true)
-            .build();
+    public static final PropertyDescriptor CREDENTIALS_FILE = 
CredentialPropertyDescriptors.CREDENTIALS_FILE;
+    public static final PropertyDescriptor ACCESS_KEY = 
CredentialPropertyDescriptors.ACCESS_KEY;
+    public static final PropertyDescriptor SECRET_KEY = 
CredentialPropertyDescriptors.SECRET_KEY;
 
     public static final PropertyDescriptor PROXY_HOST = new 
PropertyDescriptor.Builder()
             .name("Proxy Host")

http://git-wip-us.apache.org/repos/asf/nifi/blob/9bb6dcb5/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/CredentialPropertyDescriptors.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/CredentialPropertyDescriptors.java
 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/CredentialPropertyDescriptors.java
new file mode 100644
index 0000000..04330ab
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/CredentialPropertyDescriptors.java
@@ -0,0 +1,158 @@
+/*
+ * 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.aws.credentials.provider.factory;
+
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.processor.util.StandardValidators;
+
+/**
+ * Shared definitions of properties that specify various AWS credentials.
+ *
+ * @see <a 
href="http://docs.aws.amazon.com/AWSSdkDocsJava/latest/DeveloperGuide/credentials.html";>
+ *     Providing AWS Credentials in the AWS SDK for Java</a>
+ */
+public class CredentialPropertyDescriptors {
+
+    /**
+     * Specifies use of the Default Credential Provider Chain
+     *
+     * @see <a 
href="http://docs.aws.amazon.com/AWSSdkDocsJava/latest/DeveloperGuide/credentials.html#id1";>
+     *     AWS SDK: Default Credential Provider Chain
+     *     </a>
+     */
+    public static final PropertyDescriptor USE_DEFAULT_CREDENTIALS = new 
PropertyDescriptor.Builder()
+            .name("default-credentials")
+            .displayName("Use Default Credentials")
+            .expressionLanguageSupported(false)
+            .required(false)
+            .addValidator(StandardValidators.BOOLEAN_VALIDATOR)
+            .sensitive(false)
+            .allowableValues("true", "false")
+            .defaultValue("false")
+            .description("If true, uses the Default Credential chain, 
including EC2 instance profiles or roles, " +
+                "environment variables, default user credentials, etc.")
+            .build();
+
+    public static final PropertyDescriptor CREDENTIALS_FILE = new 
PropertyDescriptor.Builder()
+            .name("Credentials File")
+            .displayName("Credentials File")
+            .expressionLanguageSupported(false)
+            .required(false)
+            .addValidator(StandardValidators.FILE_EXISTS_VALIDATOR)
+            .description("Path to a file containing AWS access key and secret 
key in properties file format.")
+            .build();
+
+    public static final PropertyDescriptor ACCESS_KEY = new 
PropertyDescriptor.Builder()
+            .name("Access Key")
+            .displayName("Access Key")
+            .expressionLanguageSupported(true)
+            .required(false)
+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .sensitive(true)
+            .build();
+
+    public static final PropertyDescriptor SECRET_KEY = new 
PropertyDescriptor.Builder()
+            .name("Secret Key")
+            .displayName("Secret Key")
+            .expressionLanguageSupported(true)
+            .required(false)
+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .sensitive(true)
+            .build();
+
+    /**
+     * Specifies use of a named profile credential.
+     *
+     * @see <a 
href="http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/profile/ProfileCredentialsProvider.html";>
+     *     ProfileCredentialsProvider</a>
+     */
+    public static final PropertyDescriptor PROFILE_NAME = new 
PropertyDescriptor.Builder()
+            .name("profile-name")
+            .displayName("Profile Name")
+            .expressionLanguageSupported(true)
+            .required(false)
+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .sensitive(false)
+            .description("The AWS profile name for credentials from the 
profile configuration file.")
+            .build();
+
+    public static final PropertyDescriptor USE_ANONYMOUS_CREDENTIALS = new 
PropertyDescriptor.Builder()
+            .name("anonymous-credentials")
+            .displayName("Use Anonymous Credentials")
+            .expressionLanguageSupported(false)
+            .required(false)
+            .addValidator(StandardValidators.BOOLEAN_VALIDATOR)
+            .sensitive(false)
+            .allowableValues("true", "false")
+            .defaultValue("false")
+            .description("If true, uses Anonymous credentials")
+            .build();
+
+    /**
+     * AWS Role Arn used for cross account access
+     *
+     * @see <a 
href="http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-arns";>AWS
 ARN</a>
+     */
+    public static final PropertyDescriptor ASSUME_ROLE_ARN = new 
PropertyDescriptor.Builder()
+            .name("Assume Role ARN")
+            .displayName("Assume Role ARN")
+            .expressionLanguageSupported(false)
+            .required(false)
+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .sensitive(false)
+            .description("The AWS Role ARN for cross account access. This is 
used in conjunction with role name and session timeout")
+            .build();
+
+    /**
+     * The role name while creating aws role
+     */
+    public static final PropertyDescriptor ASSUME_ROLE_NAME = new 
PropertyDescriptor.Builder()
+            .name("Assume Role Session Name")
+            .displayName("Assume Role Session Name")
+            .expressionLanguageSupported(false)
+            .required(false)
+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .sensitive(false)
+            .description("The AWS Role Name for cross account access. This is 
used in conjunction with role ARN and session time out")
+            .build();
+
+    /**
+     * Max session time for role based credentials. The range is between 900 
and 3600 seconds.
+     */
+    public static final PropertyDescriptor MAX_SESSION_TIME = new 
PropertyDescriptor.Builder()
+            .name("Session Time")
+            .description("Session time for role based session (between 900 and 
3600 seconds). This is used in conjunction with role ARN and name")
+            .defaultValue("3600")
+            .required(false)
+            .addValidator(StandardValidators.POSITIVE_INTEGER_VALIDATOR)
+            .sensitive(false)
+            .build();
+
+    /**
+     * The ExternalId used while creating aws role.
+     */
+    public static final PropertyDescriptor ASSUME_ROLE_EXTERNAL_ID = new 
PropertyDescriptor.Builder()
+            .name("assume-role-external-id")
+            .displayName("Assume Role External ID")
+            .expressionLanguageSupported(false)
+            .required(false)
+            .addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
+            .sensitive(false)
+            .description("External ID for cross-account access. This is used 
in conjunction with role arn, " +
+                "role name, and optional session time out")
+            .build();
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/9bb6dcb5/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/CredentialsProviderFactory.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/CredentialsProviderFactory.java
 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/CredentialsProviderFactory.java
new file mode 100644
index 0000000..94f0410
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/CredentialsProviderFactory.java
@@ -0,0 +1,125 @@
+/*
+ * 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.aws.credentials.provider.factory;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.ValidationContext;
+import org.apache.nifi.components.ValidationResult;
+import 
org.apache.nifi.processors.aws.credentials.provider.factory.strategies.ExplicitDefaultCredentialsStrategy;
+import 
org.apache.nifi.processors.aws.credentials.provider.factory.strategies.AccessKeyPairCredentialsStrategy;
+import 
org.apache.nifi.processors.aws.credentials.provider.factory.strategies.FileCredentialsStrategy;
+import 
org.apache.nifi.processors.aws.credentials.provider.factory.strategies.NamedProfileCredentialsStrategy;
+import 
org.apache.nifi.processors.aws.credentials.provider.factory.strategies.AnonymousCredentialsStrategy;
+import 
org.apache.nifi.processors.aws.credentials.provider.factory.strategies.ImplicitDefaultCredentialsStrategy;
+import 
org.apache.nifi.processors.aws.credentials.provider.factory.strategies.AssumeRoleCredentialsStrategy;
+
+import com.amazonaws.auth.AWSCredentialsProvider;
+
+
+/**
+ * Generates AWS credentials in the form of AWSCredentialsProvider 
implementations for processors
+ * and controller services.  The factory supports a number of strategies for 
specifying and validating
+ * AWS credentials, interpreted as an ordered list of most-preferred to 
least-preferred.  It also supports
+ * derived credential strategies like Assume Role, which require a primary 
credential as an input.
+ *
+ * Additional strategies should implement CredentialsStrategy, then be added 
to the strategies list in the
+ * constructor.
+ *
+ * @see org.apache.nifi.processors.aws.credentials.provider.factory.strategies
+ */
+public class CredentialsProviderFactory {
+
+    private final List<CredentialsStrategy> strategies = new 
ArrayList<CredentialsStrategy>();
+
+    public CredentialsProviderFactory() {
+        // Primary Credential Strategies
+        strategies.add(new ExplicitDefaultCredentialsStrategy());
+        strategies.add(new AccessKeyPairCredentialsStrategy());
+        strategies.add(new FileCredentialsStrategy());
+        strategies.add(new NamedProfileCredentialsStrategy());
+        strategies.add(new AnonymousCredentialsStrategy());
+
+        // Implicit Default is the catch-all primary strategy
+        strategies.add(new ImplicitDefaultCredentialsStrategy());
+
+        // Derived Credential Strategies
+        strategies.add(new AssumeRoleCredentialsStrategy());
+    }
+
+    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 AWS 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 ArrayList<ValidationResult> validationFailureResults = new 
ArrayList<ValidationResult>();
+
+        for (CredentialsStrategy strategy : strategies) {
+            final Collection<ValidationResult> strategyValidationFailures = 
strategy.validate(validationContext,
+                    selectedStrategy);
+            if (strategyValidationFailures != null) {
+                validationFailureResults.addAll(strategyValidationFailures);
+            }
+        }
+
+        return validationFailureResults;
+    }
+
+    /**
+     * Produces the AWSCredentialsProvider according to the given property set 
and the strategies configured in
+     * the factory.
+     * @return AWSCredentialsProvider implementation
+     */
+    public AWSCredentialsProvider getCredentialsProvider(final 
Map<PropertyDescriptor, String> properties) {
+        final CredentialsStrategy primaryStrategy = 
selectPrimaryStrategy(properties);
+        AWSCredentialsProvider primaryCredentialsProvider = 
primaryStrategy.getCredentialsProvider(properties);
+        AWSCredentialsProvider derivedCredentialsProvider = null;
+
+        for (CredentialsStrategy strategy : strategies) {
+            if (strategy.canCreateDerivedCredential(properties)) {
+                derivedCredentialsProvider = 
strategy.getDerivedCredentialsProvider(properties,
+                        primaryCredentialsProvider);
+                break;
+            }
+        }
+
+        if (derivedCredentialsProvider != null) {
+            return derivedCredentialsProvider;
+        } else {
+            return primaryCredentialsProvider;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/9bb6dcb5/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/CredentialsStrategy.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/CredentialsStrategy.java
 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/CredentialsStrategy.java
new file mode 100644
index 0000000..d5d93a7
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/CredentialsStrategy.java
@@ -0,0 +1,75 @@
+/*
+ * 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.aws.credentials.provider.factory;
+
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.ValidationContext;
+import org.apache.nifi.components.ValidationResult;
+
+import com.amazonaws.auth.AWSCredentialsProvider;
+
+
+/**
+ * Specifies a strategy for validating and creating AWS credentials from a 
list of properties configured on a
+ * Processor, Controller Service, Reporting Service, or other component.  
Supports both primary credentials like
+ * default credentials or API keys and also derived credentials from Assume 
Role.
+ */
+public interface CredentialsStrategy {
+
+    /**
+     * Name of the strategy, suitable for displaying to a user in validation 
messages.
+     * @return strategy name
+     */
+    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);
+
+    /**
+     * Determines if this strategy can create derived credentials using the 
given properties.
+     * @return true if derived credentials can be created
+     */
+    boolean canCreateDerivedCredential(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 AWSCredentialsProvider instance for this strategy, given the 
properties defined by the user.
+     */
+    AWSCredentialsProvider getCredentialsProvider(Map<PropertyDescriptor, 
String> properties);
+
+    /**
+     * Creates an AWSCredentialsProvider instance for this strategy, given the 
properties defined by the user and
+     * the AWSCredentialsProvider from the winning primary strategy.
+     */
+    AWSCredentialsProvider 
getDerivedCredentialsProvider(Map<PropertyDescriptor, String> properties,
+                                                         
AWSCredentialsProvider primaryCredentialsProvider);
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/9bb6dcb5/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/AbstractBooleanCredentialsStrategy.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/AbstractBooleanCredentialsStrategy.java
 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/AbstractBooleanCredentialsStrategy.java
new file mode 100644
index 0000000..2c5b9a3
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/AbstractBooleanCredentialsStrategy.java
@@ -0,0 +1,70 @@
+/*
+ * 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.aws.credentials.provider.factory.strategies;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.ValidationContext;
+import org.apache.nifi.components.ValidationResult;
+import 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialsStrategy;
+
+
+/**
+ * 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("Default Credentials", new PropertyDescriptor[]{
+            strategyProperty
+        });
+        this.strategyProperty = strategyProperty;
+    }
+
+    @Override
+    public boolean canCreatePrimaryCredential(Map<PropertyDescriptor, String> 
properties) {
+        String useStrategyString = properties.get(strategyProperty);
+        Boolean useStrategy = Boolean.parseBoolean(useStrategyString);
+        return useStrategy;
+    }
+
+    @Override
+    public Collection<ValidationResult> validate(final ValidationContext 
validationContext,
+                                                 final CredentialsStrategy 
primaryStrategy) {
+        boolean thisIsSelectedStrategy = this == primaryStrategy;
+        Boolean useStrategy = 
validationContext.getProperty(strategyProperty).asBoolean();
+        if (!thisIsSelectedStrategy && useStrategy) {
+            String failureFormat = "property %1$s cannot be used with %2$s";
+            Collection<ValidationResult> validationFailureResults = new 
ArrayList<ValidationResult>();
+            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;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/9bb6dcb5/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/AbstractCredentialsStrategy.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/AbstractCredentialsStrategy.java
 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/AbstractCredentialsStrategy.java
new file mode 100644
index 0000000..29f1000
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/AbstractCredentialsStrategy.java
@@ -0,0 +1,101 @@
+/*
+ * 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.aws.credentials.provider.factory.strategies;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.ValidationContext;
+import org.apache.nifi.components.ValidationResult;
+import 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialsStrategy;
+
+import com.amazonaws.auth.AWSCredentialsProvider;
+
+
+/**
+ * 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) {
+        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<ValidationResult>();
+                }
+                validationFailureResults.add(new ValidationResult.Builder()
+                        .subject(requiredProperty.getDisplayName())
+                        .valid(false)
+                        .explanation(message).build());
+            }
+        }
+
+        return validationFailureResults;
+    }
+
+    public abstract AWSCredentialsProvider 
getCredentialsProvider(Map<PropertyDescriptor, String> properties);
+
+    public String getName() {
+        return name;
+    }
+
+
+    @Override
+    public boolean canCreateDerivedCredential(Map<PropertyDescriptor, String> 
properties) {
+        return false;
+    }
+
+    @Override
+    public AWSCredentialsProvider 
getDerivedCredentialsProvider(Map<PropertyDescriptor, String> properties,
+                                                                
AWSCredentialsProvider primaryCredentialsProvider) {
+        throw new UnsupportedOperationException();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/9bb6dcb5/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/AccessKeyPairCredentialsStrategy.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/AccessKeyPairCredentialsStrategy.java
 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/AccessKeyPairCredentialsStrategy.java
new file mode 100644
index 0000000..5cf8869
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/AccessKeyPairCredentialsStrategy.java
@@ -0,0 +1,52 @@
+/*
+ * 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.aws.credentials.provider.factory.strategies;
+
+import java.util.Map;
+
+import org.apache.nifi.components.PropertyDescriptor;
+import 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors;
+
+import com.amazonaws.auth.AWSCredentialsProvider;
+import com.amazonaws.auth.BasicAWSCredentials;
+import com.amazonaws.internal.StaticCredentialsProvider;
+
+
+/**
+ * Supports AWS credentials defined by an Access Key and Secret Key pair.
+ *
+ * @see <a 
href="http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/BasicAWSCredentials.html";>
+ *     BasicAWSCredentials</a>
+ */
+public class AccessKeyPairCredentialsStrategy extends 
AbstractCredentialsStrategy {
+
+    public AccessKeyPairCredentialsStrategy() {
+        super("Access Key Pair", new PropertyDescriptor[] {
+                CredentialPropertyDescriptors.ACCESS_KEY,
+                CredentialPropertyDescriptors.SECRET_KEY
+        });
+    }
+
+    @Override
+    public AWSCredentialsProvider 
getCredentialsProvider(Map<PropertyDescriptor, String> properties) {
+        String accessKey = 
properties.get(CredentialPropertyDescriptors.ACCESS_KEY);
+        String secretKey = 
properties.get(CredentialPropertyDescriptors.SECRET_KEY);
+        BasicAWSCredentials creds = new BasicAWSCredentials(accessKey, 
secretKey);
+        return new StaticCredentialsProvider(creds);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/9bb6dcb5/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/AnonymousCredentialsStrategy.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/AnonymousCredentialsStrategy.java
 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/AnonymousCredentialsStrategy.java
new file mode 100644
index 0000000..4f8368e
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/AnonymousCredentialsStrategy.java
@@ -0,0 +1,47 @@
+/*
+ * 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.aws.credentials.provider.factory.strategies;
+
+import java.util.Map;
+
+import org.apache.nifi.components.PropertyDescriptor;
+import 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors;
+
+import com.amazonaws.auth.AWSCredentialsProvider;
+import com.amazonaws.auth.AnonymousAWSCredentials;
+import com.amazonaws.internal.StaticCredentialsProvider;
+
+
+/**
+ * Supports Anonymous AWS credentials.
+ *
+ * @see <a 
href="http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/AnonymousAWSCredentials.html";>
+ *     AnonymousAWSCredentials</a>
+ */
+public class AnonymousCredentialsStrategy extends 
AbstractBooleanCredentialsStrategy {
+
+    public AnonymousCredentialsStrategy() {
+        super("Anonymous Credentials", 
CredentialPropertyDescriptors.USE_ANONYMOUS_CREDENTIALS);
+    }
+
+    @Override
+    public AWSCredentialsProvider 
getCredentialsProvider(Map<PropertyDescriptor, String> properties) {
+        AnonymousAWSCredentials creds = new AnonymousAWSCredentials();
+        return new StaticCredentialsProvider(creds);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/9bb6dcb5/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/AssumeRoleCredentialsStrategy.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/AssumeRoleCredentialsStrategy.java
 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/AssumeRoleCredentialsStrategy.java
new file mode 100644
index 0000000..186a97b
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/AssumeRoleCredentialsStrategy.java
@@ -0,0 +1,128 @@
+/*
+ * 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.aws.credentials.provider.factory.strategies;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Map;
+
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.components.ValidationContext;
+import org.apache.nifi.components.ValidationResult;
+import static 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors.ASSUME_ROLE_ARN;
+import static 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors.ASSUME_ROLE_NAME;
+import static 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors.MAX_SESSION_TIME;
+import static 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors.ASSUME_ROLE_EXTERNAL_ID;
+import 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialsStrategy;
+
+import com.amazonaws.auth.AWSCredentialsProvider;
+import com.amazonaws.auth.STSAssumeRoleSessionCredentialsProvider;
+
+
+/**
+ * Supports AWS credentials via Assume Role.  Assume Role is a derived 
credential strategy, requiring a primary
+ * credential to retrieve and periodically refresh temporary credentials.
+ *
+ * @see <a 
href="http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/STSAssumeRoleSessionCredentialsProvider.html";>
+ *     STSAssumeRoleCredentialsProvider</a>
+ */
+public class AssumeRoleCredentialsStrategy extends AbstractCredentialsStrategy 
{
+
+    public AssumeRoleCredentialsStrategy() {
+        super("Assume Role", new PropertyDescriptor[] {
+                ASSUME_ROLE_ARN,
+                ASSUME_ROLE_NAME,
+                MAX_SESSION_TIME,
+        });
+    }
+
+    @Override
+    public boolean canCreatePrimaryCredential(Map<PropertyDescriptor, String> 
properties) {
+        return false;
+    }
+
+    @Override
+    public boolean canCreateDerivedCredential(Map<PropertyDescriptor, String> 
properties) {
+        final String assumeRoleArn = properties.get(ASSUME_ROLE_ARN);
+        final String assumeRoleName = properties.get(ASSUME_ROLE_NAME);
+        if (assumeRoleArn != null && !assumeRoleArn.isEmpty()
+                && assumeRoleName != null && !assumeRoleName.isEmpty()) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public Collection<ValidationResult> validate(final ValidationContext 
validationContext,
+                                                 final CredentialsStrategy 
primaryStrategy) {
+        final boolean assumeRoleArnIsSet = 
validationContext.getProperty(ASSUME_ROLE_ARN).isSet();
+        final boolean assumeRoleNameIsSet = 
validationContext.getProperty(ASSUME_ROLE_NAME).isSet();
+        final Integer maxSessionTime = 
validationContext.getProperty(MAX_SESSION_TIME).asInteger();
+        final boolean assumeRoleExternalIdIsSet = 
validationContext.getProperty(ASSUME_ROLE_EXTERNAL_ID).isSet();
+
+        final Collection<ValidationResult> validationFailureResults  = new 
ArrayList<ValidationResult>();
+
+        // Both role and arn name are req if present
+        if (assumeRoleArnIsSet ^ assumeRoleNameIsSet ) {
+            validationFailureResults.add(new 
ValidationResult.Builder().input("Assume Role Arn and Name")
+                    .valid(false).explanation("Assume role requires both arn 
and name to be set").build());
+        }
+
+        // Session time only b/w 900 to 3600 sec (see sts session class)
+        if ( maxSessionTime < 900 || maxSessionTime > 3600 )
+            validationFailureResults.add(new 
ValidationResult.Builder().valid(false).input(maxSessionTime + "")
+                    .explanation(MAX_SESSION_TIME.getDisplayName() +
+                            " must be between 900 and 3600 seconds").build());
+
+        // External ID should only be provided with viable Assume Role ARN and 
Name
+        if (assumeRoleExternalIdIsSet && (!assumeRoleArnIsSet || 
!assumeRoleNameIsSet)) {
+            validationFailureResults.add(new 
ValidationResult.Builder().input("Assume Role External ID")
+                    .valid(false)
+                    .explanation("Assume role requires both arn and name to be 
set with External ID")
+                    .build());
+        }
+
+        return validationFailureResults;
+    }
+
+    @Override
+    public AWSCredentialsProvider 
getCredentialsProvider(Map<PropertyDescriptor, String> properties) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public AWSCredentialsProvider 
getDerivedCredentialsProvider(Map<PropertyDescriptor, String> properties,
+                                                                
AWSCredentialsProvider primaryCredentialsProvider) {
+        final String assumeRoleArn = properties.get(ASSUME_ROLE_ARN);
+        final String assumeRoleName = properties.get(ASSUME_ROLE_NAME);
+        String rawMaxSessionTime = properties.get(MAX_SESSION_TIME);
+        rawMaxSessionTime = (rawMaxSessionTime != null) ? rawMaxSessionTime : 
MAX_SESSION_TIME.getDefaultValue();
+        final Integer maxSessionTime = 
Integer.parseInt(rawMaxSessionTime.trim());
+        final String assumeRoleExternalId = 
properties.get(ASSUME_ROLE_EXTERNAL_ID);
+
+        STSAssumeRoleSessionCredentialsProvider.Builder builder = new 
STSAssumeRoleSessionCredentialsProvider
+                .Builder(assumeRoleArn, assumeRoleName)
+                .withLongLivedCredentialsProvider(primaryCredentialsProvider)
+                .withRoleSessionDurationSeconds(maxSessionTime);
+        if (assumeRoleExternalId != null && !assumeRoleExternalId.isEmpty()) {
+            builder = builder.withExternalId(assumeRoleExternalId);
+        }
+        final AWSCredentialsProvider credsProvider = builder.build();
+
+        return credsProvider;
+    }
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/9bb6dcb5/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/ExplicitDefaultCredentialsStrategy.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/ExplicitDefaultCredentialsStrategy.java
 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/ExplicitDefaultCredentialsStrategy.java
new file mode 100644
index 0000000..a8ac2e8
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/ExplicitDefaultCredentialsStrategy.java
@@ -0,0 +1,46 @@
+/*
+ * 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.aws.credentials.provider.factory.strategies;
+
+import java.util.Map;
+
+import org.apache.nifi.components.PropertyDescriptor;
+import 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors;
+
+import com.amazonaws.auth.AWSCredentialsProvider;
+import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
+
+
+/**
+ * Supports AWS Default Credentials.  Compared to 
ImplicitDefaultCredentialsStrategy, this strategy is designed to be
+ * visible to the user, and depends on an affirmative selection from the user.
+ *
+ * @see <a 
href="http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/DefaultAWSCredentialsProviderChain.html";>
+ *     DefaultAWSCredentialsProviderChain</a>
+ */
+public class ExplicitDefaultCredentialsStrategy extends 
AbstractBooleanCredentialsStrategy {
+
+    public ExplicitDefaultCredentialsStrategy() {
+        super("Default Credentials", 
CredentialPropertyDescriptors.USE_DEFAULT_CREDENTIALS);
+    }
+
+        @Override
+    public AWSCredentialsProvider 
getCredentialsProvider(Map<PropertyDescriptor, String> properties) {
+      return new DefaultAWSCredentialsProviderChain();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/9bb6dcb5/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/FileCredentialsStrategy.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/FileCredentialsStrategy.java
 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/FileCredentialsStrategy.java
new file mode 100644
index 0000000..7fdf93b
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/FileCredentialsStrategy.java
@@ -0,0 +1,53 @@
+/*
+ * 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.aws.credentials.provider.factory.strategies;
+
+import java.util.Map;
+
+import org.apache.nifi.components.PropertyDescriptor;
+import 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors;
+
+import com.amazonaws.auth.AWSCredentialsProvider;
+import com.amazonaws.auth.PropertiesFileCredentialsProvider;
+
+
+/**
+ * Supports AWS credentials stored in a file.  The file format should be a 
Java properties file like the following:
+ *
+ * <code>
+ * accessKey = XXXXXXXXXXXXXXXXXXXX
+ * secretKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
+ * </code>
+ *
+ *  * @see <a 
href="http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/PropertiesFileCredentialsProvider.html";>
+ *     PropertiesFileCredentialsProvider</a>
+ */
+public class FileCredentialsStrategy extends AbstractCredentialsStrategy {
+
+    public FileCredentialsStrategy() {
+        super("Credentials File", new PropertyDescriptor[] {
+                CredentialPropertyDescriptors.CREDENTIALS_FILE
+        });
+    }
+
+    @Override
+    public AWSCredentialsProvider 
getCredentialsProvider(Map<PropertyDescriptor, String> properties) {
+        String credsFile = 
properties.get(CredentialPropertyDescriptors.CREDENTIALS_FILE);
+        return new PropertiesFileCredentialsProvider(credsFile);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/9bb6dcb5/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/ImplicitDefaultCredentialsStrategy.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/ImplicitDefaultCredentialsStrategy.java
 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/ImplicitDefaultCredentialsStrategy.java
new file mode 100644
index 0000000..d9717b3
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/ImplicitDefaultCredentialsStrategy.java
@@ -0,0 +1,43 @@
+/*
+ * 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.aws.credentials.provider.factory.strategies;
+
+import java.util.Map;
+
+import org.apache.nifi.components.PropertyDescriptor;
+
+import com.amazonaws.auth.AWSCredentialsProvider;
+import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
+
+
+/**
+ * Supports AWS Default Credentials.  Compared to 
ExplicitDefaultCredentialsStrategy, 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.
+ */
+public class ImplicitDefaultCredentialsStrategy extends 
AbstractCredentialsStrategy {
+
+    public ImplicitDefaultCredentialsStrategy() {
+        super("Default Credentials", new PropertyDescriptor[]{});
+    }
+
+    @Override
+    public AWSCredentialsProvider 
getCredentialsProvider(Map<PropertyDescriptor, String> properties) {
+      return new DefaultAWSCredentialsProviderChain();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/9bb6dcb5/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/NamedProfileCredentialsStrategy.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/NamedProfileCredentialsStrategy.java
 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/NamedProfileCredentialsStrategy.java
new file mode 100644
index 0000000..294f2ed
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/factory/strategies/NamedProfileCredentialsStrategy.java
@@ -0,0 +1,48 @@
+/*
+ * 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.aws.credentials.provider.factory.strategies;
+
+import java.util.Map;
+
+import org.apache.nifi.components.PropertyDescriptor;
+import 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors;
+
+import com.amazonaws.auth.AWSCredentialsProvider;
+import com.amazonaws.auth.profile.ProfileCredentialsProvider;
+
+
+/**
+ * Supports AWS Credentials using a named profile configured in the 
credentials file (typically ~/.aws/credentials).
+ *
+ * @see <a 
href="http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/profile/ProfileCredentialsProvider.html";>
+ *     ProfileCredentialsProvider</a>
+ */
+public class NamedProfileCredentialsStrategy extends 
AbstractCredentialsStrategy {
+
+    public NamedProfileCredentialsStrategy() {
+        super("Named Profile", new PropertyDescriptor[] {
+                CredentialPropertyDescriptors.PROFILE_NAME
+        });
+    }
+
+    @Override
+    public AWSCredentialsProvider 
getCredentialsProvider(Map<PropertyDescriptor, String> properties) {
+        String profileName = 
properties.get(CredentialPropertyDescriptors.PROFILE_NAME);
+        return new ProfileCredentialsProvider(profileName);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/9bb6dcb5/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/service/AWSCredentialsProviderControllerService.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/service/AWSCredentialsProviderControllerService.java
 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/service/AWSCredentialsProviderControllerService.java
index ecc64e2..7c09bd4 100644
--- 
a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/service/AWSCredentialsProviderControllerService.java
+++ 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/credentials/provider/service/AWSCredentialsProviderControllerService.java
@@ -15,10 +15,12 @@
  * limitations under the License.
  */
 package org.apache.nifi.processors.aws.credentials.provider.service;
+
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 
 import org.apache.nifi.annotation.documentation.CapabilityDescription;
 import org.apache.nifi.annotation.documentation.Tags;
@@ -29,72 +31,55 @@ import org.apache.nifi.components.ValidationResult;
 import org.apache.nifi.controller.AbstractControllerService;
 import org.apache.nifi.controller.ConfigurationContext;
 import org.apache.nifi.processor.exception.ProcessException;
-import org.apache.nifi.processor.util.StandardValidators;
+import 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors;
+import 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialsProviderFactory;
 import org.apache.nifi.reporting.InitializationException;
 
-import static org.apache.nifi.processors.aws.AbstractAWSProcessor.ACCESS_KEY;
-import static org.apache.nifi.processors.aws.AbstractAWSProcessor.SECRET_KEY;
-import static 
org.apache.nifi.processors.aws.AbstractAWSProcessor.CREDENTIALS_FILE;
+import static 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors.USE_DEFAULT_CREDENTIALS;
+import static 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors.ACCESS_KEY;
+import static 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors.SECRET_KEY;
+import static 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors.CREDENTIALS_FILE;
+import static 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors.PROFILE_NAME;
+import static 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors.USE_ANONYMOUS_CREDENTIALS;
+import static 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors.ASSUME_ROLE_EXTERNAL_ID;
 
 import com.amazonaws.auth.AWSCredentialsProvider;
-import com.amazonaws.auth.BasicAWSCredentials;
-import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
-import com.amazonaws.auth.PropertiesFileCredentialsProvider;
-import com.amazonaws.auth.STSAssumeRoleSessionCredentialsProvider;
-import com.amazonaws.internal.StaticCredentialsProvider;
 
 /**
  * Implementation of AWSCredentialsProviderService interface
  *
  * @see AWSCredentialsProviderService
  */
-@CapabilityDescription("Defines credentials for Amazon Web Services 
processors.")
+@CapabilityDescription("Defines credentials for Amazon Web Services 
processors. " +
+        "Uses default credentials without configuration. " +
+        "Default credentials support EC2 instance profile/role, default user 
profile, environment variables, etc. " +
+        "Additional options include access key / secret key pairs, credentials 
file, named profile, and assume role credentials.")
 @Tags({ "aws", "credentials","provider" })
 public class AWSCredentialsProviderControllerService extends 
AbstractControllerService implements AWSCredentialsProviderService {
 
-    /**
-     * AWS Role Arn used for cross account access
-     *
-     * @see <a 
href="http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-arns";>AWS
 ARN</a>
-     */
-    public static final PropertyDescriptor ASSUME_ROLE_ARN = new 
PropertyDescriptor.Builder().name("Assume Role ARN")
-            
.expressionLanguageSupported(false).required(false).addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
-            .sensitive(false).description("The AWS Role ARN for cross account 
access. This is used in conjunction with role name and session 
timeout").build();
-
-    /**
-     * The role name while creating aws role
-     */
-    public static final PropertyDescriptor ASSUME_ROLE_NAME = new 
PropertyDescriptor.Builder().name("Assume Role Session Name")
-            
.expressionLanguageSupported(false).required(false).addValidator(StandardValidators.NON_EMPTY_VALIDATOR)
-            .sensitive(false).description("The aws role name for cross account 
access. This is used in conjunction with role arn and session time 
out").build();
-
-    /**
-     * Max session time for role based credentials. The range is between 900 
and 3600 seconds.
-     */
-    public static final PropertyDescriptor MAX_SESSION_TIME = new 
PropertyDescriptor.Builder()
-            .name("Session Time")
-            .description("Session time for role based session (between 900 and 
3600 seconds). This is used in conjunction with role arn and name")
-            .defaultValue("3600")
-            .required(false)
-            .addValidator(StandardValidators.POSITIVE_INTEGER_VALIDATOR)
-            .sensitive(false)
-            .build();
+    public static final PropertyDescriptor ASSUME_ROLE_ARN = 
CredentialPropertyDescriptors.ASSUME_ROLE_ARN;
+    public static final PropertyDescriptor ASSUME_ROLE_NAME = 
CredentialPropertyDescriptors.ASSUME_ROLE_NAME;
+    public static final PropertyDescriptor MAX_SESSION_TIME = 
CredentialPropertyDescriptors.MAX_SESSION_TIME;
 
     private static final List<PropertyDescriptor> properties;
 
     static {
         final List<PropertyDescriptor> props = new ArrayList<>();
+        props.add(USE_DEFAULT_CREDENTIALS);
         props.add(ACCESS_KEY);
         props.add(SECRET_KEY);
         props.add(CREDENTIALS_FILE);
+        props.add(PROFILE_NAME);
+        props.add(USE_ANONYMOUS_CREDENTIALS);
         props.add(ASSUME_ROLE_ARN);
         props.add(ASSUME_ROLE_NAME);
         props.add(MAX_SESSION_TIME);
-
+        props.add(ASSUME_ROLE_EXTERNAL_ID);
         properties = Collections.unmodifiableList(props);
     }
 
     private volatile AWSCredentialsProvider credentialsProvider;
+    protected final CredentialsProviderFactory credentialsProviderFactory = 
new CredentialsProviderFactory();
 
     @Override
     protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {
@@ -108,82 +93,16 @@ public class AWSCredentialsProviderControllerService 
extends AbstractControllerS
 
     @Override
     protected Collection<ValidationResult> customValidate(final 
ValidationContext validationContext) {
-
-        final boolean accessKeySet = 
validationContext.getProperty(ACCESS_KEY).isSet();
-        final boolean secretKeySet = 
validationContext.getProperty(SECRET_KEY).isSet();
-        final boolean assumeRoleArnIsSet = 
validationContext.getProperty(ASSUME_ROLE_ARN).isSet();
-        final boolean assumeRoleNameIsSet = 
validationContext.getProperty(ASSUME_ROLE_NAME).isSet();
-        final Integer maxSessionTime = 
validationContext.getProperty(MAX_SESSION_TIME).asInteger();
-
-        final boolean credentialsFileSet = 
validationContext.getProperty(CREDENTIALS_FILE).isSet();
-
-        final Collection<ValidationResult> validationFailureResults = new 
ArrayList<>();
-
-        // both keys are required if present
-        if ((accessKeySet && !secretKeySet) || (secretKeySet && 
!accessKeySet)) {
-            validationFailureResults.add(new 
ValidationResult.Builder().input("Access Key").valid(false)
-                    .explanation("If setting Secret Key or Access Key, must 
set both").build());
-        }
-
-        // Either keys or creds file is valid
-        if ((secretKeySet || accessKeySet) && credentialsFileSet) {
-            validationFailureResults.add(new 
ValidationResult.Builder().input("Access Key").valid(false)
-                    .explanation("Cannot set both Credentials File and Secret 
Key/Access Key").build());
-        }
-
-        // Both role and arn name are req if present
-        if (assumeRoleArnIsSet ^ assumeRoleNameIsSet ) {
-            validationFailureResults.add(new 
ValidationResult.Builder().input("Assume Role Arn and Name")
-                    .valid(false).explanation("Assume role requires both arn 
and name to be set").build());
-        }
-
-        // Session time only b/w 900 to 3600 sec (see sts session class)
-        if ( maxSessionTime < 900 || maxSessionTime > 3600 )
-            validationFailureResults.add(new 
ValidationResult.Builder().valid(false).input(maxSessionTime + "")
-                    .subject(MAX_SESSION_TIME.getDisplayName() +
-                            " can have value only between 900 and 3600 
seconds").build());
-
+        final Collection<ValidationResult> validationFailureResults =
+                credentialsProviderFactory.validate(validationContext);
         return validationFailureResults;
     }
 
     @OnEnabled
     public void onConfigured(final ConfigurationContext context) throws 
InitializationException {
-
-        final String accessKey = 
context.getProperty(ACCESS_KEY).evaluateAttributeExpressions().getValue();
-        final String secretKey = 
context.getProperty(SECRET_KEY).evaluateAttributeExpressions().getValue();
-        final String assumeRoleArn = 
context.getProperty(ASSUME_ROLE_ARN).getValue();
-        final Integer maxSessionTime = 
context.getProperty(MAX_SESSION_TIME).asInteger();
-        final String assumeRoleName = 
context.getProperty(ASSUME_ROLE_NAME).getValue();
-        final String credentialsFile = 
context.getProperty(CREDENTIALS_FILE).getValue();
-
-        // Create creds provider from file or keys
-        if (credentialsFile != null) {
-            try {
-                getLogger().debug("Creating properties file credentials 
provider");
-                credentialsProvider = new 
PropertiesFileCredentialsProvider(credentialsFile);
-            } catch (final Exception ioe) {
-                throw new ProcessException("Could not read Credentials File", 
ioe);
-            }
-        }
-
-        if (credentialsProvider == null && accessKey != null && secretKey != 
null) {
-            getLogger().debug("Creating static credentials provider");
-            credentialsProvider = new StaticCredentialsProvider(new 
BasicAWSCredentials(accessKey, secretKey));
-        }
-
-        // If no credentials explicitly provided, then create default one
-        if (credentialsProvider == null) {
-            getLogger().debug("Creating default credentials provider");
-            credentialsProvider = new DefaultAWSCredentialsProviderChain();
-        }
-
-        if (credentialsProvider != null && assumeRoleArn != null && 
assumeRoleName != null) {
-            getLogger().debug("Creating sts assume role session credentials 
provider");
-
-            credentialsProvider = new 
STSAssumeRoleSessionCredentialsProvider.Builder(assumeRoleArn, assumeRoleName)
-                    .withLongLivedCredentialsProvider(credentialsProvider)
-                    .withRoleSessionDurationSeconds(maxSessionTime).build();
-        }
+        final Map<PropertyDescriptor, String> properties = 
context.getProperties();
+        credentialsProvider = 
credentialsProviderFactory.getCredentialsProvider(context.getProperties());
+        getLogger().debug("Using credentials provider: " + 
credentialsProvider.getClass());
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/nifi/blob/9bb6dcb5/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/test/java/org/apache/nifi/processors/aws/credentials/provider/factory/MockAWSProcessor.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/test/java/org/apache/nifi/processors/aws/credentials/provider/factory/MockAWSProcessor.java
 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/test/java/org/apache/nifi/processors/aws/credentials/provider/factory/MockAWSProcessor.java
new file mode 100644
index 0000000..d76db53
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/test/java/org/apache/nifi/processors/aws/credentials/provider/factory/MockAWSProcessor.java
@@ -0,0 +1,104 @@
+/*
+ * 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.aws.credentials.provider.factory;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+
+import com.amazonaws.ClientConfiguration;
+import com.amazonaws.auth.AWSCredentials;
+import com.amazonaws.services.s3.AmazonS3Client;
+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 static 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors.USE_DEFAULT_CREDENTIALS;
+import static 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors.PROFILE_NAME;
+import static 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors.USE_ANONYMOUS_CREDENTIALS;
+import static 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors.ASSUME_ROLE_ARN;
+import static 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors.ASSUME_ROLE_NAME;
+import static 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors.MAX_SESSION_TIME;
+import static 
org.apache.nifi.processors.aws.credentials.provider.factory.CredentialPropertyDescriptors.ASSUME_ROLE_EXTERNAL_ID;
+
+import com.amazonaws.auth.AWSCredentialsProvider;
+import org.apache.nifi.processors.aws.AbstractAWSCredentialsProviderProcessor;
+
+
+/**
+ * Mock Processor implementation used to test CredentialsProviderFactory.
+ */
+public class MockAWSProcessor extends 
AbstractAWSCredentialsProviderProcessor<AmazonS3Client> {
+
+    public final List<PropertyDescriptor> properties = Arrays.asList(
+            USE_DEFAULT_CREDENTIALS,
+            ACCESS_KEY,
+            SECRET_KEY,
+            CREDENTIALS_FILE,
+            PROFILE_NAME,
+            USE_ANONYMOUS_CREDENTIALS,
+            ASSUME_ROLE_ARN,
+            ASSUME_ROLE_NAME,
+            MAX_SESSION_TIME,
+            ASSUME_ROLE_EXTERNAL_ID
+    );
+
+    @Override
+    protected List<PropertyDescriptor> getSupportedPropertyDescriptors() {
+        return properties;
+    }
+
+    @Override
+    public void onTrigger(final ProcessContext context, final ProcessSession 
session) {
+
+    }
+
+    @Override
+    protected Collection<ValidationResult> customValidate(final 
ValidationContext validationContext) {
+        CredentialsProviderFactory credsFactory = new 
CredentialsProviderFactory();
+        final Collection<ValidationResult> validationFailureResults = 
credsFactory.validate(validationContext);
+        return validationFailureResults;
+    }
+
+    /**
+     * Create client using credentials provider. This is the preferred way for 
creating clients
+     */
+    @Override
+    protected AmazonS3Client createClient(final ProcessContext context, final 
AWSCredentialsProvider credentialsProvider, final ClientConfiguration config) {
+        getLogger().info("Creating client with credentials provider");
+        final AmazonS3Client s3 = new AmazonS3Client(credentialsProvider, 
config);
+        return s3;
+    }
+
+    /**
+     * Create client using AWSCredentials
+     *
+     * @deprecated use {@link #createClient(ProcessContext, 
AWSCredentialsProvider, ClientConfiguration)} instead
+     */
+    @Override
+    protected AmazonS3Client createClient(final ProcessContext context, final 
AWSCredentials credentials, final ClientConfiguration config) {
+        getLogger().info("Creating client with awd credentials");
+
+        final AmazonS3Client s3 = new AmazonS3Client(credentials, config);
+
+        return s3;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/nifi/blob/9bb6dcb5/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/test/java/org/apache/nifi/processors/aws/credentials/provider/factory/TestCredentialsProviderFactory.java
----------------------------------------------------------------------
diff --git 
a/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/test/java/org/apache/nifi/processors/aws/credentials/provider/factory/TestCredentialsProviderFactory.java
 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/test/java/org/apache/nifi/processors/aws/credentials/provider/factory/TestCredentialsProviderFactory.java
new file mode 100644
index 0000000..ccdffe3
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-aws-bundle/nifi-aws-processors/src/test/java/org/apache/nifi/processors/aws/credentials/provider/factory/TestCredentialsProviderFactory.java
@@ -0,0 +1,201 @@
+/*
+ * 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.aws.credentials.provider.factory;
+
+import java.util.Map;
+
+import org.apache.nifi.components.PropertyDescriptor;
+import org.apache.nifi.processors.aws.s3.FetchS3Object;
+import org.apache.nifi.util.TestRunner;
+import org.apache.nifi.util.TestRunners;
+
+import com.amazonaws.auth.AnonymousAWSCredentials;
+import com.amazonaws.auth.AWSCredentials;
+import com.amazonaws.auth.AWSCredentialsProvider;
+import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
+import com.amazonaws.auth.PropertiesFileCredentialsProvider;
+import com.amazonaws.auth.STSAssumeRoleSessionCredentialsProvider;
+import com.amazonaws.auth.profile.ProfileCredentialsProvider;
+import com.amazonaws.internal.StaticCredentialsProvider;
+
+import org.junit.Assert;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Tests of the validation and credentials provider capabilities of 
CredentialsProviderFactory.
+ */
+public class TestCredentialsProviderFactory {
+
+    @Test
+    public void testImpliedDefaultCredentials() throws Throwable {
+        final TestRunner runner = 
TestRunners.newTestRunner(MockAWSProcessor.class);
+        runner.assertValid();
+
+        Map<PropertyDescriptor, String> properties = 
runner.getProcessContext().getProperties();
+        final CredentialsProviderFactory factory = new 
CredentialsProviderFactory();
+        final AWSCredentialsProvider credentialsProvider = 
factory.getCredentialsProvider(properties);
+        Assert.assertNotNull(credentialsProvider);
+        assertEquals("credentials provider should be equal", 
DefaultAWSCredentialsProviderChain.class,
+                credentialsProvider.getClass());
+    }
+
+    @Test
+    public void testExplicitDefaultCredentials() throws Throwable {
+        final TestRunner runner = 
TestRunners.newTestRunner(MockAWSProcessor.class);
+        
runner.setProperty(CredentialPropertyDescriptors.USE_DEFAULT_CREDENTIALS, 
"true");
+        runner.assertValid();
+
+        Map<PropertyDescriptor, String> properties = 
runner.getProcessContext().getProperties();
+        final CredentialsProviderFactory factory = new 
CredentialsProviderFactory();
+        final AWSCredentialsProvider credentialsProvider = 
factory.getCredentialsProvider(properties);
+        Assert.assertNotNull(credentialsProvider);
+        assertEquals("credentials provider should be equal", 
DefaultAWSCredentialsProviderChain.class,
+                credentialsProvider.getClass());
+    }
+
+    @Test
+    public void testExplicitDefaultCredentialsExclusive() throws Throwable {
+        final TestRunner runner = 
TestRunners.newTestRunner(MockAWSProcessor.class);
+        
runner.setProperty(CredentialPropertyDescriptors.USE_DEFAULT_CREDENTIALS, 
"true");
+        runner.setProperty(CredentialPropertyDescriptors.ACCESS_KEY, 
"BogusAccessKey");
+        runner.assertNotValid();
+    }
+
+    @Test
+    public void testAccessKeyPairCredentials() throws Throwable {
+        final TestRunner runner = 
TestRunners.newTestRunner(MockAWSProcessor.class);
+        
runner.setProperty(CredentialPropertyDescriptors.USE_DEFAULT_CREDENTIALS, 
"false");
+        runner.setProperty(CredentialPropertyDescriptors.ACCESS_KEY, 
"BogusAccessKey");
+        runner.setProperty(CredentialPropertyDescriptors.SECRET_KEY, 
"BogusSecretKey");
+        runner.assertValid();
+
+        Map<PropertyDescriptor, String> properties = 
runner.getProcessContext().getProperties();
+        final CredentialsProviderFactory factory = new 
CredentialsProviderFactory();
+        final AWSCredentialsProvider credentialsProvider = 
factory.getCredentialsProvider(properties);
+        Assert.assertNotNull(credentialsProvider);
+        assertEquals("credentials provider should be equal", 
StaticCredentialsProvider.class,
+                credentialsProvider.getClass());
+    }
+
+    @Test
+    public void testAccessKeyPairIncomplete() throws Throwable {
+        final TestRunner runner = 
TestRunners.newTestRunner(MockAWSProcessor.class);
+        runner.setProperty(CredentialPropertyDescriptors.ACCESS_KEY, 
"BogusAccessKey");
+        runner.assertNotValid();
+    }
+
+    @Test
+    public void testAccessKeyPairIncompleteS3() throws Throwable {
+        final TestRunner runner = 
TestRunners.newTestRunner(FetchS3Object.class);
+        runner.setProperty(CredentialPropertyDescriptors.ACCESS_KEY, 
"BogusAccessKey");
+        runner.assertNotValid();
+    }
+
+    @Test
+    public void testFileCredentials() throws Throwable {
+        final TestRunner runner = 
TestRunners.newTestRunner(MockAWSProcessor.class);
+        runner.setProperty(CredentialPropertyDescriptors.CREDENTIALS_FILE, 
"src/test/resources/mock-aws-credentials.properties");
+        runner.assertValid();
+
+        Map<PropertyDescriptor, String> properties = 
runner.getProcessContext().getProperties();
+        final CredentialsProviderFactory factory = new 
CredentialsProviderFactory();
+        final AWSCredentialsProvider credentialsProvider = 
factory.getCredentialsProvider(properties);
+        Assert.assertNotNull(credentialsProvider);
+        assertEquals("credentials provider should be equal", 
PropertiesFileCredentialsProvider.class,
+                credentialsProvider.getClass());
+    }
+
+    @Test
+    public void testAssumeRoleCredentials() throws Throwable {
+        final TestRunner runner = 
TestRunners.newTestRunner(MockAWSProcessor.class);
+        runner.setProperty(CredentialPropertyDescriptors.CREDENTIALS_FILE, 
"src/test/resources/mock-aws-credentials.properties");
+        runner.setProperty(CredentialPropertyDescriptors.ASSUME_ROLE_ARN, 
"BogusArn");
+        runner.setProperty(CredentialPropertyDescriptors.ASSUME_ROLE_NAME, 
"BogusSession");
+        runner.assertValid();
+
+        Map<PropertyDescriptor, String> properties = 
runner.getProcessContext().getProperties();
+        final CredentialsProviderFactory factory = new 
CredentialsProviderFactory();
+        final AWSCredentialsProvider credentialsProvider = 
factory.getCredentialsProvider(properties);
+        Assert.assertNotNull(credentialsProvider);
+        assertEquals("credentials provider should be equal", 
STSAssumeRoleSessionCredentialsProvider.class,
+                credentialsProvider.getClass());
+    }
+
+    @Test
+    public void testAssumeRoleCredentialsMissingARN() throws Throwable {
+        final TestRunner runner = 
TestRunners.newTestRunner(MockAWSProcessor.class);
+        runner.setProperty(CredentialPropertyDescriptors.CREDENTIALS_FILE, 
"src/test/resources/mock-aws-credentials.properties");
+        runner.setProperty(CredentialPropertyDescriptors.ASSUME_ROLE_NAME, 
"BogusSession");
+        runner.assertNotValid();
+    }
+
+    @Test
+    public void testAssumeRoleCredentialsInvalidSessionTime() throws Throwable 
{
+        final TestRunner runner = 
TestRunners.newTestRunner(MockAWSProcessor.class);
+        runner.setProperty(CredentialPropertyDescriptors.CREDENTIALS_FILE, 
"src/test/resources/mock-aws-credentials.properties");
+        runner.setProperty(CredentialPropertyDescriptors.ASSUME_ROLE_ARN, 
"BogusArn");
+        runner.setProperty(CredentialPropertyDescriptors.ASSUME_ROLE_NAME, 
"BogusSession");
+        runner.setProperty(CredentialPropertyDescriptors.MAX_SESSION_TIME, 
"10");
+        runner.assertNotValid();
+    }
+
+    @Test
+    public void testAssumeRoleExternalIdMissingArnAndName() throws Throwable {
+        final TestRunner runner = 
TestRunners.newTestRunner(MockAWSProcessor.class);
+        runner.setProperty(CredentialPropertyDescriptors.CREDENTIALS_FILE, 
"src/test/resources/mock-aws-credentials.properties");
+        
runner.setProperty(CredentialPropertyDescriptors.ASSUME_ROLE_EXTERNAL_ID, 
"BogusExternalId");
+        runner.assertNotValid();
+    }
+
+    @Test
+    public void testAnonymousCredentials() throws Throwable {
+        final TestRunner runner = 
TestRunners.newTestRunner(MockAWSProcessor.class);
+        
runner.setProperty(CredentialPropertyDescriptors.USE_ANONYMOUS_CREDENTIALS, 
"true");
+        runner.assertValid();
+
+        Map<PropertyDescriptor, String> properties = 
runner.getProcessContext().getProperties();
+        final CredentialsProviderFactory factory = new 
CredentialsProviderFactory();
+        final AWSCredentialsProvider credentialsProvider = 
factory.getCredentialsProvider(properties);
+        Assert.assertNotNull(credentialsProvider);
+        final AWSCredentials creds = credentialsProvider.getCredentials();
+        assertEquals("credentials should be equal", 
AnonymousAWSCredentials.class, creds.getClass());
+    }
+
+    @Test
+    public void testAnonymousAndDefaultCredentials() throws Throwable {
+        final TestRunner runner = 
TestRunners.newTestRunner(MockAWSProcessor.class);
+        
runner.setProperty(CredentialPropertyDescriptors.USE_DEFAULT_CREDENTIALS, 
"true");
+        
runner.setProperty(CredentialPropertyDescriptors.USE_ANONYMOUS_CREDENTIALS, 
"true");
+        runner.assertNotValid();
+    }
+
+    @Test
+    public void testNamedProfileCredentials() throws Throwable {
+        final TestRunner runner = 
TestRunners.newTestRunner(MockAWSProcessor.class);
+        
runner.setProperty(CredentialPropertyDescriptors.USE_DEFAULT_CREDENTIALS, 
"false");
+        runner.setProperty(CredentialPropertyDescriptors.PROFILE_NAME, 
"BogusProfile");
+        runner.assertValid();
+
+        Map<PropertyDescriptor, String> properties = 
runner.getProcessContext().getProperties();
+        final CredentialsProviderFactory factory = new 
CredentialsProviderFactory();
+        final AWSCredentialsProvider credentialsProvider = 
factory.getCredentialsProvider(properties);
+        Assert.assertNotNull(credentialsProvider);
+        assertEquals("credentials provider should be equal", 
ProfileCredentialsProvider.class,
+                credentialsProvider.getClass());
+    }
+}

Reply via email to