Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,3 @@ public interface CredentialsProvider {
*/
public suspend fun getCredentials(): Credentials
}

// TODO - add proxies for all the credentials providers in aws-crt-kotlin
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package aws.sdk.kotlin.runtime.auth

import aws.sdk.kotlin.runtime.AwsSdkSetting
import aws.sdk.kotlin.runtime.ConfigurationException
import aws.smithy.kotlin.runtime.util.Platform

Expand All @@ -13,20 +14,14 @@ import aws.smithy.kotlin.runtime.util.Platform
*/
public class EnvironmentCredentialsProvider
public constructor(private val getEnv: (String) -> String?) : CredentialsProvider {
public companion object {
internal const val ACCESS_KEY_ID: String = "AWS_ACCESS_KEY_ID"
internal const val SECRET_ACCESS_KEY: String = "AWS_SECRET_ACCESS_KEY"
internal const val SESSION_TOKEN: String = "AWS_SESSION_TOKEN"
}

public constructor() : this(Platform::getenv)

private fun requireEnv(variable: String): String =
getEnv(variable) ?: throw ConfigurationException("Unable to get value from environment variable $variable")

override suspend fun getCredentials(): Credentials = Credentials(
accessKeyId = requireEnv(ACCESS_KEY_ID),
secretAccessKey = requireEnv(SECRET_ACCESS_KEY),
sessionToken = getEnv(SESSION_TOKEN),
accessKeyId = requireEnv(AwsSdkSetting.AwsAccessKeyId.environmentVariable),
secretAccessKey = requireEnv(AwsSdkSetting.AwsSecretAccessKey.environmentVariable),
sessionToken = getEnv(AwsSdkSetting.AwsSessionToken.environmentVariable),
Comment on lines -16 to +25
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much cleaner!

)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package aws.sdk.kotlin.runtime.auth

import aws.sdk.kotlin.runtime.AwsSdkSetting
import aws.sdk.kotlin.runtime.ConfigurationException
import aws.sdk.kotlin.runtime.testing.runSuspendTest
import kotlin.test.Test
Expand All @@ -17,33 +18,33 @@ class EnvironmentCredentialsProviderTest {
@Test
fun `it should read from environment variables (incl session token)`() = runSuspendTest {
val provider = provider(
EnvironmentCredentialsProvider.ACCESS_KEY_ID to "abc",
EnvironmentCredentialsProvider.SECRET_ACCESS_KEY to "def",
EnvironmentCredentialsProvider.SESSION_TOKEN to "ghi",
AwsSdkSetting.AwsAccessKeyId.environmentVariable to "abc",
AwsSdkSetting.AwsSecretAccessKey.environmentVariable to "def",
AwsSdkSetting.AwsSessionToken.environmentVariable to "ghi",
)
assertEquals(provider.getCredentials(), Credentials("abc", "def", "ghi"))
}

@Test
fun `it should read from environment variables (excl session token)`() = runSuspendTest {
val provider = provider(
EnvironmentCredentialsProvider.ACCESS_KEY_ID to "abc",
EnvironmentCredentialsProvider.SECRET_ACCESS_KEY to "def",
AwsSdkSetting.AwsAccessKeyId.environmentVariable to "abc",
AwsSdkSetting.AwsSecretAccessKey.environmentVariable to "def",
)
assertEquals(provider.getCredentials(), Credentials("abc", "def", null))
}

@Test
fun `it should throw an exception on missing access key`() = runSuspendTest {
fun `it should throw an exception on missing access key`(): Unit = runSuspendTest {
assertFailsWith<ConfigurationException> {
provider(EnvironmentCredentialsProvider.SECRET_ACCESS_KEY to "def").getCredentials()
provider(AwsSdkSetting.AwsSecretAccessKey.environmentVariable to "def").getCredentials()
}
}

@Test
fun `it should throw an exception on missing secret key`() = runSuspendTest {
fun `it should throw an exception on missing secret key`(): Unit = runSuspendTest {
assertFailsWith<ConfigurationException> {
provider(EnvironmentCredentialsProvider.ACCESS_KEY_ID to "abc").getCredentials()
provider(AwsSdkSetting.AwsAccessKeyId.environmentVariable to "abc").getCredentials()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/

package aws.sdk.kotlin.runtime

// NOTE: The JVM property names MUST match the ones defined in the Java SDK for any setting added.
// see: https://github.com/aws/aws-sdk-java-v2/blob/master/core/sdk-core/src/main/java/software/amazon/awssdk/core/SdkSystemSetting.java

/**
* Settings to configure SDK runtime behavior
*/
@InternalSdkApi
public sealed class AwsSdkSetting<T> (
/**
* The name of the corresponding environment variable that configures the setting
*/
public val environmentVariable: String,

/**
* The name of the corresponding JVM system property that configures the setting
*/
public val jvmProperty: String,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment

Would we ever have a case for a setting available via environment but not the jvm?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought of that and wasn't sure. I slept on it and think the answer is probably no. If there is an environment variable there ought to be a corresponding JVM property. I don't see any cases in the Java SDK where this isn't true FWIW.


/**
* The default value (if one exists)
*/
public val defaultValue: T? = null
) {
/**
* Configure the AWS access key ID.
*
* This value will not be ignored if the [AwsSecretAccessKey] is not specified.
*/
public object AwsAccessKeyId : AwsSdkSetting<String>("AWS_ACCESS_KEY_ID", "aws.accessKeyId")

/**
* Configure the AWS secret access key.
*
* This value will not be ignored if the [AwsAccessKeyId] is not specified.
*/
public object AwsSecretAccessKey : AwsSdkSetting<String>("AWS_SECRET_ACCESS_KEY", "aws.secretAccessKey")

/**
* Configure the AWS session token.
*/
public object AwsSessionToken : AwsSdkSetting<String>("AWS_SESSION_TOKEN", "aws.sessionToken")

/**
* Configure the default region.
*/
public object AwsRegion : AwsSdkSetting<String>("AWS_REGION", "aws.region")
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,11 @@

package aws.sdk.kotlin.runtime.regions.providers

// FIXME - this probably needs to be expect/actual to customize the chain per/target platform (and definitely needs per/platform tests)

/**
* [AwsRegionProvider] that looks for region in this order:
* 1. Check `aws.region` system property (JVM only)
* 2. Check the `AWS_REGION` and `AWS_DEFAULT_REGION` environment variable(s) (JVM, Node, Native)
* 2. Check the `AWS_REGION` environment variable (JVM, Node, Native)
* 3. Check the AWS config files/profile for region information
* 4. If running on EC2, check the EC2 metadata service for region
*/
public class DefaultAwsRegionProviderChain : AwsRegionProviderChain {
public constructor() : super(EnvironmentRegionProvider())
}
public expect class DefaultAwsRegionProviderChain public constructor() : AwsRegionProvider
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@

package aws.sdk.kotlin.runtime.regions.providers

import aws.sdk.kotlin.runtime.AwsSdkSetting
import aws.smithy.kotlin.runtime.util.Platform

private const val AWS_ENVIRON_REGION = "AWS_REGION"

/**
* Provide a mapping from key to value
*/
Expand All @@ -17,13 +16,13 @@ public fun interface Environment {
}

/**
* [AwsRegionProvider] that checks `AWS_REGION` and `AWS_DEFAULT` region environment variables
* [AwsRegionProvider] that checks `AWS_REGION` region environment variable
* @param environ the environment mapping to lookup keys in (defaults to the system environment)
*/
public class EnvironmentRegionProvider(
private val environ: Environment
) : AwsRegionProvider {
public constructor() : this(Platform::getenv)

override suspend fun getRegion(): String? = environ.get(AWS_ENVIRON_REGION)
override suspend fun getRegion(): String? = environ.get(AwsSdkSetting.AwsRegion.environmentVariable)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/

package aws.sdk.kotlin.runtime.regions.providers

public actual class DefaultAwsRegionProviderChain public actual constructor() :
AwsRegionProvider,
AwsRegionProviderChain(
JvmSystemPropRegionProvider(),
EnvironmentRegionProvider()
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/

package aws.sdk.kotlin.runtime.regions.providers

import aws.sdk.kotlin.runtime.AwsSdkSetting

/**
* [AwsRegionProvider] that checks `aws.region` system property
*/
internal class JvmSystemPropRegionProvider : AwsRegionProvider {
override suspend fun getRegion(): String? = System.getProperty(AwsSdkSetting.AwsRegion.jvmProperty, null)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/

package aws.sdk.kotlin.runtime.regions.providers

import aws.sdk.kotlin.runtime.AwsSdkSetting
import aws.sdk.kotlin.runtime.testing.runSuspendTest
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
import kotlin.test.assertNull

class JvmSystemPropRegionProviderTest {

@Test
fun testGetRegion() = runSuspendTest {
val provider = JvmSystemPropRegionProvider()

assertNull(provider.getRegion())

System.setProperty(AwsSdkSetting.AwsRegion.jvmProperty, "us-east-1")
assertEquals("us-east-1", provider.getRegion())
}
}