diff --git a/runtime/auth/http-auth/api/http-auth.api b/runtime/auth/http-auth/api/http-auth.api index d47a5a9c79..bbdec31e71 100644 --- a/runtime/auth/http-auth/api/http-auth.api +++ b/runtime/auth/http-auth/api/http-auth.api @@ -62,6 +62,8 @@ public abstract interface class aws/smithy/kotlin/runtime/http/auth/CloseableBea public final class aws/smithy/kotlin/runtime/http/auth/EnvironmentBearerTokenProvider : aws/smithy/kotlin/runtime/http/auth/BearerTokenProvider { public fun (Ljava/lang/String;Laws/smithy/kotlin/runtime/util/PlatformProvider;)V public synthetic fun (Ljava/lang/String;Laws/smithy/kotlin/runtime/util/PlatformProvider;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Ljava/lang/String;Laws/smithy/kotlin/runtime/util/PlatformProvider;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/String;Laws/smithy/kotlin/runtime/util/PlatformProvider;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public fun resolve (Laws/smithy/kotlin/runtime/collections/Attributes;Lkotlin/coroutines/Continuation;)Ljava/lang/Object; } diff --git a/runtime/auth/http-auth/common/src/aws/smithy/kotlin/runtime/http/auth/EnvironmentBearerTokenProvider.kt b/runtime/auth/http-auth/common/src/aws/smithy/kotlin/runtime/http/auth/EnvironmentBearerTokenProvider.kt index ffe37b60b0..4863f0c6e7 100644 --- a/runtime/auth/http-auth/common/src/aws/smithy/kotlin/runtime/http/auth/EnvironmentBearerTokenProvider.kt +++ b/runtime/auth/http-auth/common/src/aws/smithy/kotlin/runtime/http/auth/EnvironmentBearerTokenProvider.kt @@ -4,25 +4,37 @@ */ package aws.smithy.kotlin.runtime.http.auth +import aws.smithy.kotlin.runtime.businessmetrics.SmithyBusinessMetric +import aws.smithy.kotlin.runtime.businessmetrics.emitBusinessMetric import aws.smithy.kotlin.runtime.collections.Attributes -import aws.smithy.kotlin.runtime.collections.emptyAttributes +import aws.smithy.kotlin.runtime.collections.mutableAttributes import aws.smithy.kotlin.runtime.time.Instant import aws.smithy.kotlin.runtime.util.PlatformProvider /** - * A [BearerTokenProvider] that extracts the bearer token from the target environment variable. + * A [BearerTokenProvider] that extracts the bearer token from JVM system properties or environment variables. */ public class EnvironmentBearerTokenProvider( - private val key: String, + private val sysPropKey: String, + private val envKey: String, private val platform: PlatformProvider = PlatformProvider.System, ) : BearerTokenProvider { + @Deprecated("This constructor does not support a parameter for a system property key and will be removed in version 1.6.x") + public constructor( + envKey: String, + platform: PlatformProvider = PlatformProvider.System, + ) : this("", envKey, platform) + override suspend fun resolve(attributes: Attributes): BearerToken { - val bearerToken = platform.getenv(key) - ?: error("$key environment variable is not set") + val bearerToken = sysPropKey.takeUnless(String::isBlank)?.let(platform::getProperty) + ?: platform.getenv(envKey) + if (bearerToken.isNullOrBlank()) throw IllegalStateException("""Missing values for system property "$sysPropKey" and environment variable "$envKey"""") return object : BearerToken { override val token: String = bearerToken - override val attributes: Attributes = emptyAttributes() + override val attributes: Attributes = mutableAttributes().apply { + emitBusinessMetric(SmithyBusinessMetric.BEARER_SERVICE_ENV_VARS) + } override val expiration: Instant? = null } } diff --git a/runtime/auth/http-auth/common/test/aws/smithy/kotlin/runtime/http/auth/EnvironmentBearerTokenProviderTest.kt b/runtime/auth/http-auth/common/test/aws/smithy/kotlin/runtime/http/auth/EnvironmentBearerTokenProviderTest.kt index e98e8083d5..c4f6161eff 100644 --- a/runtime/auth/http-auth/common/test/aws/smithy/kotlin/runtime/http/auth/EnvironmentBearerTokenProviderTest.kt +++ b/runtime/auth/http-auth/common/test/aws/smithy/kotlin/runtime/http/auth/EnvironmentBearerTokenProviderTest.kt @@ -1,6 +1,5 @@ package aws.smithy.kotlin.runtime.http.auth -import aws.smithy.kotlin.runtime.collections.emptyAttributes import aws.smithy.kotlin.runtime.util.TestPlatformProvider import kotlinx.coroutines.test.runTest import kotlin.test.Test @@ -9,27 +8,65 @@ import kotlin.test.assertFailsWith class EnvironmentBearerTokenProviderTest { @Test - fun testResolveWithValidToken() = runTest { + fun testResolveFromEnvVar() = runTest { val provider = EnvironmentBearerTokenProvider( - "TEST_TOKEN", - TestPlatformProvider(mutableMapOf("TEST_TOKEN" to "test-bearer-token")), + "TEST_SYS_PROPS_TOKEN", + "TEST_ENV_TOKEN", + TestPlatformProvider( + env = mapOf("TEST_ENV_TOKEN" to "test-env-bearer-token"), + ), ) val token = provider.resolve() - assertEquals("test-bearer-token", token.token) + assertEquals("test-env-bearer-token", token.token) + } + + @Test + fun testResolveFromSysProps() = runTest { + val provider = EnvironmentBearerTokenProvider( + "TEST_SYS_PROPS_TOKEN", + "TEST_ENV_TOKEN", + TestPlatformProvider( + props = mapOf("TEST_SYS_PROPS_TOKEN" to "test-sys-props-bearer-token"), + ), + ) + + val token = provider.resolve() + + assertEquals("test-sys-props-bearer-token", token.token) + } + + @Test + fun testResolutionOrder() = runTest { + val provider = EnvironmentBearerTokenProvider( + "TEST_SYS_PROPS_TOKEN", + "TEST_ENV_TOKEN", + TestPlatformProvider( + props = mapOf("TEST_SYS_PROPS_TOKEN" to "test-sys-props-bearer-token"), + env = mapOf("TEST_ENV_TOKEN" to "test-env-bearer-token"), + ), + ) + + val token = provider.resolve() + + assertEquals("test-sys-props-bearer-token", token.token) } @Test fun testResolveWithMissingToken() = runTest { val provider = EnvironmentBearerTokenProvider( "MISSING_TEST_TOKEN", - TestPlatformProvider(mutableMapOf()), + "MISSING_TEST_TOKEN", + TestPlatformProvider( + env = mapOf("TEST_TOKEN" to "test-env-bearer-token"), + props = mapOf("TEST_TOKEN" to "test-sys-props-bearer-token"), + ), ) val exception = assertFailsWith { - provider.resolve(emptyAttributes()) + provider.resolve() } - assertEquals("MISSING_TEST_TOKEN environment variable is not set", exception.message) + assertEquals("Missing values for system property \"MISSING_TEST_TOKEN\" and environment variable \"MISSING_TEST_TOKEN\"", exception.message) } } diff --git a/runtime/runtime-core/api/runtime-core.api b/runtime/runtime-core/api/runtime-core.api index 91855f6e4d..fcc7f6727a 100644 --- a/runtime/runtime-core/api/runtime-core.api +++ b/runtime/runtime-core/api/runtime-core.api @@ -107,6 +107,7 @@ public final class aws/smithy/kotlin/runtime/businessmetrics/SmithyBusinessMetri public static final field ACCOUNT_ID_MODE_DISABLED Laws/smithy/kotlin/runtime/businessmetrics/SmithyBusinessMetric; public static final field ACCOUNT_ID_MODE_PREFERRED Laws/smithy/kotlin/runtime/businessmetrics/SmithyBusinessMetric; public static final field ACCOUNT_ID_MODE_REQUIRED Laws/smithy/kotlin/runtime/businessmetrics/SmithyBusinessMetric; + public static final field BEARER_SERVICE_ENV_VARS Laws/smithy/kotlin/runtime/businessmetrics/SmithyBusinessMetric; public static final field FLEXIBLE_CHECKSUMS_REQ_CRC32 Laws/smithy/kotlin/runtime/businessmetrics/SmithyBusinessMetric; public static final field FLEXIBLE_CHECKSUMS_REQ_CRC32C Laws/smithy/kotlin/runtime/businessmetrics/SmithyBusinessMetric; public static final field FLEXIBLE_CHECKSUMS_REQ_SHA1 Laws/smithy/kotlin/runtime/businessmetrics/SmithyBusinessMetric; diff --git a/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/businessmetrics/BusinessMetricsUtils.kt b/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/businessmetrics/BusinessMetricsUtils.kt index 13a88aea29..3b3d4e9072 100644 --- a/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/businessmetrics/BusinessMetricsUtils.kt +++ b/runtime/runtime-core/common/src/aws/smithy/kotlin/runtime/businessmetrics/BusinessMetricsUtils.kt @@ -102,6 +102,7 @@ public enum class SmithyBusinessMetric(public override val identifier: String) : FLEXIBLE_CHECKSUMS_REQ_WHEN_REQUIRED("a"), FLEXIBLE_CHECKSUMS_RES_WHEN_SUPPORTED("b"), FLEXIBLE_CHECKSUMS_RES_WHEN_REQUIRED("c"), + BEARER_SERVICE_ENV_VARS("3"), ; override fun toString(): String = identifier