Merge pull request #1 from ethkatnic/aws-sdk-v1-to-v2

MultiLang AWS SDK v1 to v2
This commit is contained in:
ethkatnic 2024-09-04 11:11:23 -07:00 committed by GitHub
commit 42a7768f1c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 207 additions and 320 deletions

View file

@ -27,10 +27,6 @@
<artifactId>amazon-kinesis-client-multilang</artifactId> <artifactId>amazon-kinesis-client-multilang</artifactId>
<properties>
<aws-java-sdk.version>1.12.668</aws-java-sdk.version>
</properties>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>software.amazon.kinesis</groupId> <groupId>software.amazon.kinesis</groupId>
@ -43,32 +39,6 @@
<version>${awssdk.version}</version> <version>${awssdk.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-core</artifactId>
<version>${aws-java-sdk.version}</version>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-cbor</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-sts</artifactId>
<version>${aws-java-sdk.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.projectlombok</groupId> <groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId> <artifactId>lombok</artifactId>

View file

@ -15,13 +15,14 @@
package software.amazon.kinesis.multilang; package software.amazon.kinesis.multilang;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import com.amazonaws.regions.Regions;
import com.google.common.base.CaseFormat; import com.google.common.base.CaseFormat;
import lombok.AccessLevel; import lombok.AccessLevel;
import lombok.Getter; import lombok.Getter;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import software.amazon.awssdk.regions.Region;
/** /**
* Key-Value pairs which may be nested in, and extracted from, a property value * Key-Value pairs which may be nested in, and extracted from, a property value
@ -73,8 +74,13 @@ public enum NestedPropertyKey {
* @see <a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#concepts-regions">Available Regions</a> * @see <a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html#concepts-regions">Available Regions</a>
*/ */
ENDPOINT_REGION { ENDPOINT_REGION {
void visit(final NestedPropertyProcessor processor, final String region) { void visit(final NestedPropertyProcessor processor, final String regionName) {
processor.acceptEndpointRegion(Regions.fromName(region)); List<Region> validRegions = Region.regions();
Region region = Region.of(regionName);
if (!validRegions.contains(region)) {
throw new IllegalArgumentException("Invalid region name: " + regionName);
}
processor.acceptEndpointRegion(region);
} }
}, },

View file

@ -14,7 +14,7 @@
*/ */
package software.amazon.kinesis.multilang; package software.amazon.kinesis.multilang;
import com.amazonaws.regions.Regions; import software.amazon.awssdk.regions.Region;
/** /**
* Defines methods to process {@link NestedPropertyKey}s. * Defines methods to process {@link NestedPropertyKey}s.
@ -28,7 +28,7 @@ public interface NestedPropertyProcessor {
* (e.g., https://sns.us-west-1.amazonaws.com, sns.us-west-1.amazonaws.com) * (e.g., https://sns.us-west-1.amazonaws.com, sns.us-west-1.amazonaws.com)
* @param signingRegion the region to use for SigV4 signing of requests (e.g. us-west-1) * @param signingRegion the region to use for SigV4 signing of requests (e.g. us-west-1)
* *
* @see #acceptEndpointRegion(Regions) * @see #acceptEndpointRegion(Region)
* @see <a href="https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/client/builder/AwsClientBuilder.EndpointConfiguration.html"> * @see <a href="https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/client/builder/AwsClientBuilder.EndpointConfiguration.html">
* AwsClientBuilder.EndpointConfiguration</a> * AwsClientBuilder.EndpointConfiguration</a>
*/ */
@ -42,7 +42,7 @@ public interface NestedPropertyProcessor {
* *
* @see #acceptEndpoint(String, String) * @see #acceptEndpoint(String, String)
*/ */
void acceptEndpointRegion(Regions region); void acceptEndpointRegion(Region region);
/** /**
* Set the external id, an optional field to designate who can assume an IAM role. * Set the external id, an optional field to designate who can assume an IAM role.

View file

@ -1,86 +0,0 @@
/*
* Copyright 2023 Amazon.com, Inc. or its affiliates.
* Licensed 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 software.amazon.kinesis.multilang.auth;
import java.util.Arrays;
import com.amazonaws.auth.AWSSessionCredentials;
import com.amazonaws.auth.AWSSessionCredentialsProvider;
import com.amazonaws.auth.STSAssumeRoleSessionCredentialsProvider;
import com.amazonaws.auth.STSAssumeRoleSessionCredentialsProvider.Builder;
import com.amazonaws.client.builder.AwsClientBuilder.EndpointConfiguration;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.securitytoken.AWSSecurityTokenService;
import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClient;
import software.amazon.kinesis.multilang.NestedPropertyKey;
import software.amazon.kinesis.multilang.NestedPropertyProcessor;
/**
* An {@link AWSSessionCredentialsProvider} that is backed by STSAssumeRole.
*/
public class KclSTSAssumeRoleSessionCredentialsProvider
implements AWSSessionCredentialsProvider, NestedPropertyProcessor {
private final Builder builder;
private final STSAssumeRoleSessionCredentialsProvider provider;
/**
*
* @param params vararg parameters which must include roleArn at index=0,
* and roleSessionName at index=1
*/
public KclSTSAssumeRoleSessionCredentialsProvider(final String[] params) {
this(params[0], params[1], Arrays.copyOfRange(params, 2, params.length));
}
public KclSTSAssumeRoleSessionCredentialsProvider(
final String roleArn, final String roleSessionName, final String... params) {
builder = new Builder(roleArn, roleSessionName);
NestedPropertyKey.parse(this, params);
provider = builder.build();
}
@Override
public AWSSessionCredentials getCredentials() {
return provider.getCredentials();
}
@Override
public void refresh() {
// do nothing
}
@Override
public void acceptEndpoint(final String serviceEndpoint, final String signingRegion) {
final EndpointConfiguration endpoint = new EndpointConfiguration(serviceEndpoint, signingRegion);
final AWSSecurityTokenService stsClient = AWSSecurityTokenServiceClient.builder()
.withEndpointConfiguration(endpoint)
.build();
builder.withStsClient(stsClient);
}
@Override
public void acceptEndpointRegion(final Regions region) {
final AWSSecurityTokenService stsClient =
AWSSecurityTokenServiceClient.builder().withRegion(region).build();
builder.withStsClient(stsClient);
}
@Override
public void acceptExternalId(final String externalId) {
builder.withExternalId(externalId);
}
}

View file

@ -0,0 +1,59 @@
package software.amazon.kinesis.multilang.auth;
import java.net.URI;
import java.util.Arrays;
import software.amazon.awssdk.auth.credentials.AwsCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.sts.StsClient;
import software.amazon.awssdk.services.sts.StsClientBuilder;
import software.amazon.awssdk.services.sts.auth.StsAssumeRoleCredentialsProvider;
import software.amazon.awssdk.services.sts.model.AssumeRoleRequest;
import software.amazon.awssdk.services.sts.model.AssumeRoleRequest.Builder;
import software.amazon.kinesis.multilang.NestedPropertyKey;
import software.amazon.kinesis.multilang.NestedPropertyProcessor;
public class KclStsAssumeRoleCredentialsProvider implements AwsCredentialsProvider, NestedPropertyProcessor {
private final Builder assumeRoleRequestBuilder;
private final StsClientBuilder stsClientBuilder;
public KclStsAssumeRoleCredentialsProvider(String[] params) {
this(params[0], params[1], Arrays.copyOfRange(params, 2, params.length));
}
public KclStsAssumeRoleCredentialsProvider(String roleArn, String roleSessionName, String... params) {
this.assumeRoleRequestBuilder =
AssumeRoleRequest.builder().roleArn(roleArn).roleSessionName(roleSessionName);
this.stsClientBuilder = StsClient.builder();
NestedPropertyKey.parse(this, params);
}
@Override
public AwsCredentials resolveCredentials() {
StsAssumeRoleCredentialsProvider provider = StsAssumeRoleCredentialsProvider.builder()
.refreshRequest(assumeRoleRequestBuilder.build())
.stsClient(stsClientBuilder.build())
.build();
return provider.resolveCredentials();
}
@Override
public void acceptEndpoint(String serviceEndpoint, String signingRegion) {
if (!serviceEndpoint.startsWith("http://") && !serviceEndpoint.startsWith("https://")) {
serviceEndpoint = "https://" + serviceEndpoint;
}
stsClientBuilder.endpointOverride(URI.create(serviceEndpoint));
stsClientBuilder.region(Region.of(signingRegion));
}
@Override
public void acceptEndpointRegion(Region region) {
stsClientBuilder.region(region);
}
@Override
public void acceptExternalId(String externalId) {
assumeRoleRequestBuilder.externalId(externalId);
}
}

View file

@ -15,6 +15,8 @@
package software.amazon.kinesis.multilang.config; package software.amazon.kinesis.multilang.config;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -22,40 +24,42 @@ import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.AWSCredentialsProviderChain;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProviderChain;
/** /**
* Get AWSCredentialsProvider property. * Get AwsCredentialsProvider property.
*/ */
@Slf4j @Slf4j
class AWSCredentialsProviderPropertyValueDecoder implements IPropertyValueDecoder<AWSCredentialsProvider> { class AwsCredentialsProviderPropertyValueDecoder implements IPropertyValueDecoder<AwsCredentialsProvider> {
private static final String LIST_DELIMITER = ","; private static final String LIST_DELIMITER = ",";
private static final String ARG_DELIMITER = "|"; private static final String ARG_DELIMITER = "|";
/** /**
* Constructor. * Constructor.
*/ */
AWSCredentialsProviderPropertyValueDecoder() {} AwsCredentialsProviderPropertyValueDecoder() {}
/** /**
* Get AWSCredentialsProvider property. * Get AwsCredentialsProvider property.
* *
* @param value * @param value
* property value as String * property value as String
* @return corresponding variable in correct type * @return corresponding variable in correct type
*/ */
@Override @Override
public AWSCredentialsProvider decodeValue(String value) { public AwsCredentialsProvider decodeValue(String value) {
if (value != null) { if (value != null) {
List<String> providerNames = getProviderNames(value); List<String> providerNames = getProviderNames(value);
List<AWSCredentialsProvider> providers = getValidCredentialsProviders(providerNames); List<AwsCredentialsProvider> providers = getValidCredentialsProviders(providerNames);
AWSCredentialsProvider[] ps = new AWSCredentialsProvider[providers.size()]; AwsCredentialsProvider[] ps = new AwsCredentialsProvider[providers.size()];
providers.toArray(ps); providers.toArray(ps);
return new AWSCredentialsProviderChain(providers); return AwsCredentialsProviderChain.builder()
.credentialsProviders(providers)
.build();
} else { } else {
throw new IllegalArgumentException("Property AWSCredentialsProvider is missing."); throw new IllegalArgumentException("Property AwsCredentialsProvider is missing.");
} }
} }
@ -63,25 +67,25 @@ class AWSCredentialsProviderPropertyValueDecoder implements IPropertyValueDecode
* @return list of supported types * @return list of supported types
*/ */
@Override @Override
public List<Class<AWSCredentialsProvider>> getSupportedTypes() { public List<Class<AwsCredentialsProvider>> getSupportedTypes() {
return Collections.singletonList(AWSCredentialsProvider.class); return Collections.singletonList(AwsCredentialsProvider.class);
} }
/** /**
* Convert string list to a list of valid credentials providers. * Convert string list to a list of valid credentials providers.
*/ */
private static List<AWSCredentialsProvider> getValidCredentialsProviders(List<String> providerNames) { private static List<AwsCredentialsProvider> getValidCredentialsProviders(List<String> providerNames) {
List<AWSCredentialsProvider> credentialsProviders = new ArrayList<>(); List<AwsCredentialsProvider> credentialsProviders = new ArrayList<>();
for (String providerName : providerNames) { for (String providerName : providerNames) {
final String[] nameAndArgs = providerName.split("\\" + ARG_DELIMITER); final String[] nameAndArgs = providerName.split("\\" + ARG_DELIMITER);
final Class<? extends AWSCredentialsProvider> clazz; final Class<? extends AwsCredentialsProvider> clazz;
try { try {
final Class<?> c = Class.forName(nameAndArgs[0]); final Class<?> c = Class.forName(nameAndArgs[0]);
if (!AWSCredentialsProvider.class.isAssignableFrom(c)) { if (!AwsCredentialsProvider.class.isAssignableFrom(c)) {
continue; continue;
} }
clazz = (Class<? extends AWSCredentialsProvider>) c; clazz = (Class<? extends AwsCredentialsProvider>) c;
} catch (ClassNotFoundException cnfe) { } catch (ClassNotFoundException cnfe) {
// Providers are a product of prefixed Strings to cover multiple // Providers are a product of prefixed Strings to cover multiple
// namespaces (e.g., "Foo" -> { "some.auth.Foo", "kcl.auth.Foo" }). // namespaces (e.g., "Foo" -> { "some.auth.Foo", "kcl.auth.Foo" }).
@ -90,7 +94,7 @@ class AWSCredentialsProviderPropertyValueDecoder implements IPropertyValueDecode
} }
log.info("Attempting to construct {}", clazz); log.info("Attempting to construct {}", clazz);
AWSCredentialsProvider provider = null; AwsCredentialsProvider provider = null;
if (nameAndArgs.length > 1) { if (nameAndArgs.length > 1) {
final String[] varargs = Arrays.copyOfRange(nameAndArgs, 1, nameAndArgs.length); final String[] varargs = Arrays.copyOfRange(nameAndArgs, 1, nameAndArgs.length);
@ -113,6 +117,20 @@ class AWSCredentialsProviderPropertyValueDecoder implements IPropertyValueDecode
provider = constructProvider(providerName, clazz::newInstance); provider = constructProvider(providerName, clazz::newInstance);
} }
if (provider == null) {
// if still not found, try empty create() method
try {
Method createMethod = clazz.getDeclaredMethod("create");
if (Modifier.isStatic(createMethod.getModifiers())) {
provider = constructProvider(providerName, () -> clazz.cast(createMethod.invoke(null)));
} else {
log.warn("Found non-static create() method in {}", providerName);
}
} catch (NoSuchMethodException e) {
// No create() method found for class
}
}
if (provider != null) { if (provider != null) {
credentialsProviders.add(provider); credentialsProviders.add(provider);
} }
@ -136,39 +154,37 @@ class AWSCredentialsProviderPropertyValueDecoder implements IPropertyValueDecode
private static List<String> getPossibleFullClassNames(final String provider) { private static List<String> getPossibleFullClassNames(final String provider) {
return Stream.of( return Stream.of(
// Customer provides a short name of common providers in com.amazonaws.auth package
// (e.g., any classes implementing the AWSCredentialsProvider interface)
// @see
// http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/AWSCredentialsProvider.html
"com.amazonaws.auth.",
// Customer provides a short name of a provider offered by this multi-lang package // Customer provides a short name of a provider offered by this multi-lang package
"software.amazon.kinesis.multilang.auth.", "software.amazon.kinesis.multilang.auth.",
// Customer provides a short name of common providers in software.amazon.awssdk.auth.credentials
// package (e.g., any classes implementing the AwsCredentialsProvider interface)
// @see
// https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/AwsCredentialsProvider.html
"software.amazon.awssdk.auth.credentials.",
// Customer provides a fully-qualified provider name, or a custom credentials provider // Customer provides a fully-qualified provider name, or a custom credentials provider
// (e.g., com.amazonaws.auth.ClasspathFileCredentialsProvider, org.mycompany.FooProvider) // (e.g., org.mycompany.FooProvider)
"") "")
.map(prefix -> prefix + provider) .map(prefix -> prefix + provider)
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@FunctionalInterface @FunctionalInterface
private interface CredentialsProviderConstructor<T extends AWSCredentialsProvider> { private interface CredentialsProviderConstructor<T extends AwsCredentialsProvider> {
T construct() T construct()
throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException; throws IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException;
} }
/** /**
* Attempts to construct an {@link AWSCredentialsProvider}. * Attempts to construct an {@link AwsCredentialsProvider}.
* *
* @param providerName Raw, unmodified provider name. Should there be an * @param providerName Raw, unmodified provider name. Should there be an
* Exeception during construction, this parameter will be logged. * Exception during construction, this parameter will be logged.
* @param constructor supplier-like function that will perform the construction * @param constructor supplier-like function that will perform the construction
* @return the constructed provider, if successful; otherwise, null * @return the constructed provider, if successful; otherwise, null
* *
* @param <T> type of the CredentialsProvider to construct * @param <T> type of the CredentialsProvider to construct
*/ */
private static <T extends AWSCredentialsProvider> T constructProvider( private static <T extends AwsCredentialsProvider> T constructProvider(
final String providerName, final CredentialsProviderConstructor<T> constructor) { final String providerName, final CredentialsProviderConstructor<T> constructor) {
try { try {
return constructor.construct(); return constructor.construct();

View file

@ -55,7 +55,6 @@ import software.amazon.kinesis.leases.ShardPrioritization;
import software.amazon.kinesis.lifecycle.LifecycleConfig; import software.amazon.kinesis.lifecycle.LifecycleConfig;
import software.amazon.kinesis.metrics.MetricsConfig; import software.amazon.kinesis.metrics.MetricsConfig;
import software.amazon.kinesis.metrics.MetricsLevel; import software.amazon.kinesis.metrics.MetricsLevel;
import software.amazon.kinesis.multilang.config.credentials.V2CredentialWrapper;
import software.amazon.kinesis.processor.ProcessorConfig; import software.amazon.kinesis.processor.ProcessorConfig;
import software.amazon.kinesis.processor.ShardRecordProcessorFactory; import software.amazon.kinesis.processor.ShardRecordProcessorFactory;
import software.amazon.kinesis.retrieval.RetrievalConfig; import software.amazon.kinesis.retrieval.RetrievalConfig;
@ -282,9 +281,9 @@ public class MultiLangDaemonConfiguration {
ArrayConverter arrayConverter = new ArrayConverter(String[].class, new StringConverter()); ArrayConverter arrayConverter = new ArrayConverter(String[].class, new StringConverter());
arrayConverter.setDelimiter(','); arrayConverter.setDelimiter(',');
convertUtilsBean.register(arrayConverter, String[].class); convertUtilsBean.register(arrayConverter, String[].class);
AWSCredentialsProviderPropertyValueDecoder oldCredentialsDecoder = AwsCredentialsProviderPropertyValueDecoder credentialsDecoder =
new AWSCredentialsProviderPropertyValueDecoder(); new AwsCredentialsProviderPropertyValueDecoder();
Function<String, ?> converter = s -> new V2CredentialWrapper(oldCredentialsDecoder.decodeValue(s)); Function<String, ?> converter = credentialsDecoder::decodeValue;
this.kinesisCredentialsProvider = new BuilderDynaBean( this.kinesisCredentialsProvider = new BuilderDynaBean(
AwsCredentialsProvider.class, convertUtilsBean, converter, CREDENTIALS_DEFAULT_SEARCH_PATH); AwsCredentialsProvider.class, convertUtilsBean, converter, CREDENTIALS_DEFAULT_SEARCH_PATH);

View file

@ -1,52 +0,0 @@
/*
* Copyright 2019 Amazon.com, Inc. or its affiliates.
* Licensed 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 software.amazon.kinesis.multilang.config.credentials;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.AWSSessionCredentials;
import lombok.RequiredArgsConstructor;
import software.amazon.awssdk.auth.credentials.AwsCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.AwsSessionCredentials;
@RequiredArgsConstructor
public class V2CredentialWrapper implements AwsCredentialsProvider {
private final AWSCredentialsProvider oldCredentialsProvider;
@Override
public AwsCredentials resolveCredentials() {
AWSCredentials current = oldCredentialsProvider.getCredentials();
if (current instanceof AWSSessionCredentials) {
return AwsSessionCredentials.create(
current.getAWSAccessKeyId(),
current.getAWSSecretKey(),
((AWSSessionCredentials) current).getSessionToken());
}
return new AwsCredentials() {
@Override
public String accessKeyId() {
return current.getAWSAccessKeyId();
}
@Override
public String secretAccessKey() {
return current.getAWSSecretKey();
}
};
}
}

View file

@ -65,7 +65,7 @@ public class MultiLangDaemonConfigTest {
String properties = String.format( String properties = String.format(
"executableName = %s\n" "executableName = %s\n"
+ "applicationName = %s\n" + "applicationName = %s\n"
+ "AWSCredentialsProvider = DefaultAWSCredentialsProviderChain\n" + "AWSCredentialsProvider = DefaultCredentialsProvider\n"
+ "processingLanguage = malbolge\n" + "processingLanguage = malbolge\n"
+ "regionName = %s\n", + "regionName = %s\n",
EXE, APPLICATION_NAME, "us-east-1"); EXE, APPLICATION_NAME, "us-east-1");
@ -182,7 +182,7 @@ public class MultiLangDaemonConfigTest {
@Test @Test
public void testPropertyValidation() { public void testPropertyValidation() {
String propertiesNoExecutableName = "applicationName = testApp \n" + "streamName = fakeStream \n" String propertiesNoExecutableName = "applicationName = testApp \n" + "streamName = fakeStream \n"
+ "AWSCredentialsProvider = DefaultAWSCredentialsProviderChain\n" + "processingLanguage = malbolge"; + "AWSCredentialsProvider = DefaultCredentialsProvider\n" + "processingLanguage = malbolge";
ClassLoader classLoader = Mockito.mock(ClassLoader.class); ClassLoader classLoader = Mockito.mock(ClassLoader.class);
Mockito.doReturn(new ByteArrayInputStream(propertiesNoExecutableName.getBytes())) Mockito.doReturn(new ByteArrayInputStream(propertiesNoExecutableName.getBytes()))

View file

@ -14,11 +14,11 @@
*/ */
package software.amazon.kinesis.multilang; package software.amazon.kinesis.multilang;
import com.amazonaws.regions.Regions;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner; import org.mockito.runners.MockitoJUnitRunner;
import software.amazon.awssdk.regions.Region;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@ -64,9 +64,9 @@ public class NestedPropertyKeyTest {
@Test @Test
public void testEndpointRegion() { public void testEndpointRegion() {
final Regions expectedRegion = Regions.GovCloud; final Region expectedRegion = Region.US_GOV_WEST_1;
parse(mockProcessor, createKey(ENDPOINT_REGION, expectedRegion.getName())); parse(mockProcessor, createKey(ENDPOINT_REGION, expectedRegion.id()));
verify(mockProcessor).acceptEndpointRegion(expectedRegion); verify(mockProcessor).acceptEndpointRegion(expectedRegion);
} }

View file

@ -31,15 +31,14 @@ public class KclSTSAssumeRoleSessionCredentialsProviderTest {
*/ */
@Test @Test
public void testConstructorWithoutOptionalParams() { public void testConstructorWithoutOptionalParams() {
new KclSTSAssumeRoleSessionCredentialsProvider(new String[] {ARN, SESSION_NAME}); new KclStsAssumeRoleCredentialsProvider(new String[] {ARN, SESSION_NAME});
} }
@Test @Test
public void testAcceptEndpoint() { public void testAcceptEndpoint() {
// discovered exception during e2e testing; therefore, this test is // discovered exception during e2e testing; therefore, this test is
// to simply verify the constructed STS client doesn't go *boom* // to simply verify the constructed STS client doesn't go *boom*
final KclSTSAssumeRoleSessionCredentialsProvider provider = final KclStsAssumeRoleCredentialsProvider provider = new KclStsAssumeRoleCredentialsProvider(ARN, SESSION_NAME);
new KclSTSAssumeRoleSessionCredentialsProvider(ARN, SESSION_NAME);
provider.acceptEndpoint("endpoint", "us-east-1"); provider.acceptEndpoint("endpoint", "us-east-1");
} }
@ -53,7 +52,7 @@ public class KclSTSAssumeRoleSessionCredentialsProviderTest {
} }
} }
private static class VarArgsSpy extends KclSTSAssumeRoleSessionCredentialsProvider { private static class VarArgsSpy extends KclStsAssumeRoleCredentialsProvider {
private String externalId; private String externalId;

View file

@ -16,16 +16,16 @@ package software.amazon.kinesis.multilang.config;
import java.util.Arrays; import java.util.Arrays;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.AWSCredentialsProviderChain;
import com.amazonaws.auth.BasicAWSCredentials;
import lombok.ToString; import lombok.ToString;
import org.hamcrest.Description; import org.hamcrest.Description;
import org.hamcrest.Matcher; import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeDiagnosingMatcher; import org.hamcrest.TypeSafeDiagnosingMatcher;
import org.junit.Test; import org.junit.Test;
import software.amazon.kinesis.multilang.auth.KclSTSAssumeRoleSessionCredentialsProvider; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProviderChain;
import software.amazon.kinesis.multilang.auth.KclStsAssumeRoleCredentialsProvider;
import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.instanceOf;
@ -40,10 +40,10 @@ public class AWSCredentialsProviderPropertyValueDecoderTest {
private final String credentialName1 = AlwaysSucceedCredentialsProvider.class.getName(); private final String credentialName1 = AlwaysSucceedCredentialsProvider.class.getName();
private final String credentialName2 = ConstructorCredentialsProvider.class.getName(); private final String credentialName2 = ConstructorCredentialsProvider.class.getName();
private final AWSCredentialsProviderPropertyValueDecoder decoder = new AWSCredentialsProviderPropertyValueDecoder(); private final AwsCredentialsProviderPropertyValueDecoder decoder = new AwsCredentialsProviderPropertyValueDecoder();
@ToString @ToString
private static class AWSCredentialsMatcher extends TypeSafeDiagnosingMatcher<AWSCredentialsProvider> { private static class AWSCredentialsMatcher extends TypeSafeDiagnosingMatcher<AwsCredentialsProvider> {
private final Matcher<String> akidMatcher; private final Matcher<String> akidMatcher;
private final Matcher<String> secretMatcher; private final Matcher<String> secretMatcher;
@ -52,12 +52,12 @@ public class AWSCredentialsProviderPropertyValueDecoderTest {
public AWSCredentialsMatcher(String akid, String secret) { public AWSCredentialsMatcher(String akid, String secret) {
this.akidMatcher = equalTo(akid); this.akidMatcher = equalTo(akid);
this.secretMatcher = equalTo(secret); this.secretMatcher = equalTo(secret);
this.classMatcher = instanceOf(AWSCredentialsProviderChain.class); this.classMatcher = instanceOf(AwsCredentialsProviderChain.class);
} }
@Override @Override
protected boolean matchesSafely(AWSCredentialsProvider item, Description mismatchDescription) { protected boolean matchesSafely(AwsCredentialsProvider item, Description mismatchDescription) {
AWSCredentials actual = item.getCredentials(); AwsCredentials actual = item.resolveCredentials();
boolean matched = true; boolean matched = true;
if (!classMatcher.matches(item)) { if (!classMatcher.matches(item)) {
@ -65,12 +65,12 @@ public class AWSCredentialsProviderPropertyValueDecoderTest {
matched = false; matched = false;
} }
if (!akidMatcher.matches(actual.getAWSAccessKeyId())) { if (!akidMatcher.matches(actual.accessKeyId())) {
akidMatcher.describeMismatch(actual.getAWSAccessKeyId(), mismatchDescription); akidMatcher.describeMismatch(actual.accessKeyId(), mismatchDescription);
matched = false; matched = false;
} }
if (!secretMatcher.matches(actual.getAWSSecretKey())) { if (!secretMatcher.matches(actual.secretAccessKey())) {
secretMatcher.describeMismatch(actual.getAWSSecretKey(), mismatchDescription); secretMatcher.describeMismatch(actual.secretAccessKey(), mismatchDescription);
matched = false; matched = false;
} }
return matched; return matched;
@ -90,25 +90,25 @@ public class AWSCredentialsProviderPropertyValueDecoderTest {
@Test @Test
public void testSingleProvider() { public void testSingleProvider() {
AWSCredentialsProvider provider = decoder.decodeValue(credentialName1); AwsCredentialsProvider provider = decoder.decodeValue(credentialName1);
assertThat(provider, hasCredentials(TEST_ACCESS_KEY_ID, TEST_SECRET_KEY)); assertThat(provider, hasCredentials(TEST_ACCESS_KEY_ID, TEST_SECRET_KEY));
} }
@Test @Test
public void testTwoProviders() { public void testTwoProviders() {
AWSCredentialsProvider provider = decoder.decodeValue(credentialName1 + "," + credentialName1); AwsCredentialsProvider provider = decoder.decodeValue(credentialName1 + "," + credentialName1);
assertThat(provider, hasCredentials(TEST_ACCESS_KEY_ID, TEST_SECRET_KEY)); assertThat(provider, hasCredentials(TEST_ACCESS_KEY_ID, TEST_SECRET_KEY));
} }
@Test @Test
public void testProfileProviderWithOneArg() { public void testProfileProviderWithOneArg() {
AWSCredentialsProvider provider = decoder.decodeValue(credentialName2 + "|arg"); AwsCredentialsProvider provider = decoder.decodeValue(credentialName2 + "|arg");
assertThat(provider, hasCredentials("arg", "blank")); assertThat(provider, hasCredentials("arg", "blank"));
} }
@Test @Test
public void testProfileProviderWithTwoArgs() { public void testProfileProviderWithTwoArgs() {
AWSCredentialsProvider provider = decoder.decodeValue(credentialName2 + "|arg1|arg2"); AwsCredentialsProvider provider = decoder.decodeValue(credentialName2 + "|arg1|arg2");
assertThat(provider, hasCredentials("arg1", "arg2")); assertThat(provider, hasCredentials("arg1", "arg2"));
} }
@ -118,10 +118,10 @@ public class AWSCredentialsProviderPropertyValueDecoderTest {
@Test @Test
public void testKclAuthProvider() { public void testKclAuthProvider() {
for (final String className : Arrays.asList( for (final String className : Arrays.asList(
KclSTSAssumeRoleSessionCredentialsProvider.class.getName(), // fully-qualified name KclStsAssumeRoleCredentialsProvider.class.getName(), // fully-qualified name
KclSTSAssumeRoleSessionCredentialsProvider.class.getSimpleName() // name-only; needs prefix KclStsAssumeRoleCredentialsProvider.class.getSimpleName() // name-only; needs prefix
)) { )) {
final AWSCredentialsProvider provider = decoder.decodeValue(className + "|arn|sessionName"); final AwsCredentialsProvider provider = decoder.decodeValue(className + "|arn|sessionName");
assertNotNull(className, provider); assertNotNull(className, provider);
} }
} }
@ -135,28 +135,24 @@ public class AWSCredentialsProviderPropertyValueDecoderTest {
final String className = VarArgCredentialsProvider.class.getName(); final String className = VarArgCredentialsProvider.class.getName();
final String encodedValue = className + "|" + String.join("|", args); final String encodedValue = className + "|" + String.join("|", args);
final AWSCredentialsProvider provider = decoder.decodeValue(encodedValue); final AwsCredentialsProvider provider = decoder.decodeValue(encodedValue);
assertEquals(Arrays.toString(args), provider.getCredentials().getAWSAccessKeyId()); assertEquals(Arrays.toString(args), provider.resolveCredentials().accessKeyId());
} }
/** /**
* This credentials provider will always succeed * This credentials provider will always succeed
*/ */
public static class AlwaysSucceedCredentialsProvider implements AWSCredentialsProvider { public static class AlwaysSucceedCredentialsProvider implements AwsCredentialsProvider {
@Override @Override
public AWSCredentials getCredentials() { public AwsCredentials resolveCredentials() {
return new BasicAWSCredentials(TEST_ACCESS_KEY_ID, TEST_SECRET_KEY); return AwsBasicCredentials.create(TEST_ACCESS_KEY_ID, TEST_SECRET_KEY);
} }
@Override
public void refresh() {}
} }
/** /**
* This credentials provider needs a constructor call to instantiate it * This credentials provider needs a constructor call to instantiate it
*/ */
public static class ConstructorCredentialsProvider implements AWSCredentialsProvider { public static class ConstructorCredentialsProvider implements AwsCredentialsProvider {
private String arg1; private String arg1;
private String arg2; private String arg2;
@ -172,15 +168,12 @@ public class AWSCredentialsProviderPropertyValueDecoderTest {
} }
@Override @Override
public AWSCredentials getCredentials() { public AwsCredentials resolveCredentials() {
return new BasicAWSCredentials(arg1, arg2); return AwsBasicCredentials.create(arg1, arg2);
} }
@Override
public void refresh() {}
} }
private static class VarArgCredentialsProvider implements AWSCredentialsProvider { private static class VarArgCredentialsProvider implements AwsCredentialsProvider {
private final String[] args; private final String[] args;
@ -189,13 +182,10 @@ public class AWSCredentialsProviderPropertyValueDecoderTest {
} }
@Override @Override
public AWSCredentials getCredentials() { public AwsCredentials resolveCredentials() {
// KISS solution to surface the constructor args // KISS solution to surface the constructor args
final String flattenedArgs = Arrays.toString(args); final String flattenedArgs = Arrays.toString(args);
return new BasicAWSCredentials(flattenedArgs, flattenedArgs); return AwsBasicCredentials.create(flattenedArgs, flattenedArgs);
} }
@Override
public void refresh() {}
} }
} }

View file

@ -22,15 +22,14 @@ import java.util.Date;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils; import org.apache.commons.lang3.exception.ExceptionUtils;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner; import org.mockito.runners.MockitoJUnitRunner;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentials;
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
import software.amazon.kinesis.common.InitialPositionInStream; import software.amazon.kinesis.common.InitialPositionInStream;
import software.amazon.kinesis.metrics.MetricsLevel; import software.amazon.kinesis.metrics.MetricsLevel;
@ -526,71 +525,52 @@ public class KinesisClientLibConfiguratorTest {
/** /**
* This credentials provider will always succeed * This credentials provider will always succeed
*/ */
public static class AlwaysSucceedCredentialsProvider implements AWSCredentialsProvider { public static class AlwaysSucceedCredentialsProvider implements AwsCredentialsProvider {
@Override @Override
public AWSCredentials getCredentials() { public AwsCredentials resolveCredentials() {
return new BasicAWSCredentials("a", "b"); return AwsBasicCredentials.create("a", "b");
} }
@Override
public void refresh() {}
} }
/** /**
* This credentials provider will always succeed * This credentials provider will always succeed
*/ */
public static class AlwaysSucceedCredentialsProviderKinesis implements AWSCredentialsProvider { public static class AlwaysSucceedCredentialsProviderKinesis implements AwsCredentialsProvider {
@Override @Override
public AWSCredentials getCredentials() { public AwsCredentials resolveCredentials() {
return new BasicAWSCredentials("", ""); return AwsBasicCredentials.create("DUMMY_ACCESS_KEY_ID", "DUMMY_SECRET_ACCESS_KEY");
} }
@Override
public void refresh() {}
} }
/** /**
* This credentials provider will always succeed * This credentials provider will always succeed
*/ */
public static class AlwaysSucceedCredentialsProviderDynamoDB implements AWSCredentialsProvider { public static class AlwaysSucceedCredentialsProviderDynamoDB implements AwsCredentialsProvider {
@Override @Override
public AWSCredentials getCredentials() { public AwsCredentials resolveCredentials() {
return new BasicAWSCredentials("", ""); return AwsBasicCredentials.create("DUMMY_ACCESS_KEY_ID", "DUMMY_SECRET_ACCESS_KEY");
} }
@Override
public void refresh() {}
} }
/** /**
* This credentials provider will always succeed * This credentials provider will always succeed
*/ */
public static class AlwaysSucceedCredentialsProviderCloudWatch implements AWSCredentialsProvider { public static class AlwaysSucceedCredentialsProviderCloudWatch implements AwsCredentialsProvider {
@Override @Override
public AWSCredentials getCredentials() { public AwsCredentials resolveCredentials() {
return new BasicAWSCredentials("", ""); return AwsBasicCredentials.create("DUMMY_ACCESS_KEY_ID", "DUMMY_SECRET_ACCESS_KEY");
} }
@Override
public void refresh() {}
} }
/** /**
* This credentials provider will always fail * This credentials provider will always fail
*/ */
public static class AlwaysFailCredentialsProvider implements AWSCredentialsProvider { public static class AlwaysFailCredentialsProvider implements AwsCredentialsProvider {
@Override @Override
public AWSCredentials getCredentials() { public AwsCredentials resolveCredentials() {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
@Override
public void refresh() {}
} }
private MultiLangDaemonConfiguration getConfiguration(String configString) { private MultiLangDaemonConfiguration getConfiguration(String configString) {

View file

@ -19,8 +19,8 @@ applicationName = MultiLangTest
# Users can change the credentials provider the KCL will use to retrieve credentials. # Users can change the credentials provider the KCL will use to retrieve credentials.
# The DefaultAWSCredentialsProviderChain checks several other providers, which is # The DefaultAWSCredentialsProviderChain checks several other providers, which is
# described here: # described here:
# http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/DefaultAWSCredentialsProviderChain.html # https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/DefaultCredentialsProvider.html
AWSCredentialsProvider = DefaultAWSCredentialsProviderChain AWSCredentialsProvider = DefaultCredentialsProvider
# Appended to the user agent of the KCL. Does not impact the functionality of the # Appended to the user agent of the KCL. Does not impact the functionality of the
# KCL in any other way. # KCL in any other way.

View file

@ -7,21 +7,22 @@ However, KCL now provides better extensibility to handle, and be enhanced to han
This document should help multilang customers configure a suitable `CredentialProvider` (or contribute changes to support a new use case!). This document should help multilang customers configure a suitable `CredentialProvider` (or contribute changes to support a new use case!).
## Sample Provider Configuration ## Sample Provider Configuration
DEPRECATED: StsAssumeRoleCredentialsProvider can no longer be constructed in this way:
```
AWSCredentialsProvider = StsAssumeRoleCredentialsProvider|<arn>|<sessionName>`
```
In a Properties file, an `AWSCredentialsProperty` configuration might look like: To create a [StsAssumeRoleCredentialsProvider][sts-assume-provider], see KclStsAssumeRoleCredentialsProvider below.
```
AWSCredentialsProvider = STSAssumeRoleSessionCredentialsProvider|<arn>|<sessionName>
```
This basic configuration creates an [STSAssumeRoleSessionCredentialsProvider][sts-assume-provider] with an ARN and session name.
While functional, this configuration is limited.
For example, this configuration cannot set a regional endpoint (e.g., VPC use case).
Leveraging nested properties, an `AWSCredentialsProperty` value might change to: You can create a default [DefaultCredentialsProvider][default-credentials-provider] or [AnonymousCredentialsProvider][anonymous-credentials-provider]
by passing it in the config like:
``` ```
AWSCredentialsProvider = KclSTSAssumeRoleSessionCredentialsProvider|<arn>|<sessionName>\ AWSCredentialsProvider = DefaultCredentialsProvider
|endpointRegion=us-east-1|externalId=spartacus
``` ```
N.B. Backslash (`\`) is for multi-line legibility and is not required.
If you wish to customize properties on an AWS SDK provider that uses a builder, like the StsASsumeRoleCredentialsProvider,
you will need to wrap this provider class, provide a constructor, and manage the build of the provider.
See implementation of [KclStsAssumeRoleCredentialsProvider][kcl-sts-provider]
## Nested Properties ## Nested Properties
@ -36,9 +37,6 @@ The [Backus-Naur form][bnf] of the value:
<nested-value ::= <string> # this depends on the nested key <nested-value ::= <string> # this depends on the nested key
``` ```
In general, required parameters are passed directly to the class' constructor
(e.g., [STSAssumeRoleSessionCredentialsProvider(String, String)][sts-assume-provider-constructor]).
Nested properties are a custom mapping provided by KCL multilang, and do not exist in the AWS SDK. Nested properties are a custom mapping provided by KCL multilang, and do not exist in the AWS SDK.
See [NestedPropertyKey][nested-property-key] for the supported keys, and details on their expected values. See [NestedPropertyKey][nested-property-key] for the supported keys, and details on their expected values.
@ -54,18 +52,26 @@ A backwards-compatible addition might look like:
} }
``` ```
### KclSTSAssumeRoleSessionCredentialsProvider Leveraging nested properties, an `AWSCredentialsProperty` value might look like:
KCL multilang includes a [custom nested property processor for `STSAssumeRole`][kcl-sts-provider].
Multilang configurations that use `STSAssumeRoleSessionCredentialsProvider` need only prefix `Kcl` to exercise this new provider:
``` ```
AWSCredentialsProvider = KclSTSAssumeRoleSessionCredentialsProvider|<arn>|<sessionName> AWSCredentialsProvider = KclSTSAssumeRoleSessionCredentialsProvider|<arn>|<sessionName>\
|endpointRegion=us-east-1|externalId=spartacus
```
N.B. Backslash (`\`) is for multi-line legibility and is not required.
### KclStsAssumeRoleCredentialsProvider
KCL multilang includes a [custom nested property processor for `StsAssumeRole`][kcl-sts-provider].
Multilang configurations that use `StsAssumeRoleSessionCredentialsProvider` need only prefix `Kcl` to exercise this new provider:
```
AWSCredentialsProvider = KclStsAssumeRoleCredentialsProvider|<arn>|<sessionName>
``` ```
[aws-credentials-provider]: https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/AwsCredentialsProvider.html [aws-credentials-provider]: https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/AwsCredentialsProvider.html
[bnf]: https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form [bnf]: https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form
[kcl-sts-provider]: /amazon-kinesis-client-multilang/src/main/java/software/amazon/kinesis/multilang/auth/KclSTSAssumeRoleSessionCredentialsProvider.java [kcl-sts-provider]: /amazon-kinesis-client-multilang/src/main/java/software/amazon/kinesis/multilang/auth/KclStsAssumeRoleCredentialsProvider.java
[nested-property-key]: /amazon-kinesis-client-multilang/src/main/java/software/amazon/kinesis/multilang/NestedPropertyKey.java [nested-property-key]: /amazon-kinesis-client-multilang/src/main/java/software/amazon/kinesis/multilang/NestedPropertyKey.java
[nested-property-processor]: /amazon-kinesis-client-multilang/src/main/java/software/amazon/kinesis/multilang/NestedPropertyProcessor.java [nested-property-processor]: /amazon-kinesis-client-multilang/src/main/java/software/amazon/kinesis/multilang/NestedPropertyProcessor.java
[sts-assume-provider]: https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/STSAssumeRoleSessionCredentialsProvider.html [sts-assume-provider]: https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/services/sts/auth/StsAssumeRoleCredentialsProvider.html
[sts-assume-provider-constructor]: https://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/auth/STSAssumeRoleSessionCredentialsProvider.html#STSAssumeRoleSessionCredentialsProvider-java.lang.String-java.lang.String- [default-credentials-provider]: https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/auth/credentials/DefaultCredentialsProvider.html
[anonymous-credentials-provider]: https://sdk.amazonaws.com/java/api/2.0.0-preview-11/software/amazon/awssdk/auth/credentials/AnonymousCredentialsProvider.html