diff --git a/.changes/cae05a44-3c24-4ba3-9a0b-85aaaa7d9f1f.json b/.changes/cae05a44-3c24-4ba3-9a0b-85aaaa7d9f1f.json new file mode 100644 index 00000000000..d752dc8fa07 --- /dev/null +++ b/.changes/cae05a44-3c24-4ba3-9a0b-85aaaa7d9f1f.json @@ -0,0 +1,8 @@ +{ + "id": "cae05a44-3c24-4ba3-9a0b-85aaaa7d9f1f", + "type": "bugfix", + "description": "Correctly route applicationId to requests made by internal clients", + "issues": [ + "https://github.com/aws/aws-sdk-kotlin/issues/1717" + ] +} \ No newline at end of file diff --git a/aws-runtime/aws-config/api/aws-config.api b/aws-runtime/aws-config/api/aws-config.api index ce35a2d9ef5..9b55244e258 100644 --- a/aws-runtime/aws-config/api/aws-config.api +++ b/aws-runtime/aws-config/api/aws-config.api @@ -265,6 +265,11 @@ public abstract interface class aws/sdk/kotlin/runtime/config/AwsSdkClientConfig public abstract fun setUseFips (Ljava/lang/Boolean;)V } +public final class aws/sdk/kotlin/runtime/config/AwsSdkClientOption { + public static final field INSTANCE Laws/sdk/kotlin/runtime/config/AwsSdkClientOption; + public final fun getApplicationId ()Laws/smithy/kotlin/runtime/collections/AttributeKey; +} + public final class aws/sdk/kotlin/runtime/config/AwsSdkSetting { public static final field INSTANCE Laws/sdk/kotlin/runtime/config/AwsSdkSetting; public final fun getAwsAccessKeyId ()Laws/smithy/kotlin/runtime/config/EnvironmentSetting; diff --git a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/SsoCredentialsProvider.kt b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/SsoCredentialsProvider.kt index 3cb4304b5f8..a8f90cbd508 100644 --- a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/SsoCredentialsProvider.kt +++ b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/SsoCredentialsProvider.kt @@ -8,6 +8,7 @@ package aws.sdk.kotlin.runtime.auth.credentials import aws.sdk.kotlin.runtime.auth.credentials.internal.credentials import aws.sdk.kotlin.runtime.auth.credentials.internal.sso.SsoClient import aws.sdk.kotlin.runtime.auth.credentials.internal.sso.getRoleCredentials +import aws.sdk.kotlin.runtime.config.AwsSdkClientOption import aws.sdk.kotlin.runtime.http.interceptors.businessmetrics.AwsBusinessMetric import aws.sdk.kotlin.runtime.http.interceptors.businessmetrics.withBusinessMetric import aws.smithy.kotlin.runtime.auth.awscredentials.* @@ -102,6 +103,7 @@ public class SsoCredentialsProvider public constructor( httpClient = this@SsoCredentialsProvider.httpClient telemetryProvider = telemetry logMode = attributes.getOrNull(SdkClientOption.LogMode) + applicationId = attributes.getOrNull(AwsSdkClientOption.ApplicationId) // FIXME - create an anonymous credential provider to explicitly avoid default chain creation (technically the transform should remove need for sigv4 cred provider since it's all anon auth) } diff --git a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/StsAssumeRoleCredentialsProvider.kt b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/StsAssumeRoleCredentialsProvider.kt index e84781e95ea..486f5a98465 100644 --- a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/StsAssumeRoleCredentialsProvider.kt +++ b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/StsAssumeRoleCredentialsProvider.kt @@ -12,6 +12,7 @@ import aws.sdk.kotlin.runtime.auth.credentials.internal.sts.assumeRole import aws.sdk.kotlin.runtime.auth.credentials.internal.sts.model.PolicyDescriptorType import aws.sdk.kotlin.runtime.auth.credentials.internal.sts.model.RegionDisabledException import aws.sdk.kotlin.runtime.auth.credentials.internal.sts.model.Tag +import aws.sdk.kotlin.runtime.config.AwsSdkClientOption import aws.sdk.kotlin.runtime.config.AwsSdkSetting import aws.sdk.kotlin.runtime.http.interceptors.businessmetrics.AwsBusinessMetric import aws.sdk.kotlin.runtime.http.interceptors.businessmetrics.withBusinessMetric @@ -106,6 +107,7 @@ public class StsAssumeRoleCredentialsProvider( httpClient = provider.httpClient telemetryProvider = telemetry logMode = attributes.getOrNull(SdkClientOption.LogMode) + applicationId = attributes.getOrNull(AwsSdkClientOption.ApplicationId) } val resp = try { diff --git a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/StsWebIdentityCredentialsProvider.kt b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/StsWebIdentityCredentialsProvider.kt index 3f5147f1968..b13f3ff2d03 100644 --- a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/StsWebIdentityCredentialsProvider.kt +++ b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/auth/credentials/StsWebIdentityCredentialsProvider.kt @@ -10,6 +10,7 @@ import aws.sdk.kotlin.runtime.auth.credentials.internal.credentials import aws.sdk.kotlin.runtime.auth.credentials.internal.sts.StsClient import aws.sdk.kotlin.runtime.auth.credentials.internal.sts.assumeRoleWithWebIdentity import aws.sdk.kotlin.runtime.auth.credentials.internal.sts.model.PolicyDescriptorType +import aws.sdk.kotlin.runtime.config.AwsSdkClientOption import aws.sdk.kotlin.runtime.config.AwsSdkSetting import aws.sdk.kotlin.runtime.http.interceptors.businessmetrics.AwsBusinessMetric import aws.sdk.kotlin.runtime.http.interceptors.businessmetrics.withBusinessMetric @@ -122,6 +123,7 @@ public class StsWebIdentityCredentialsProvider( // NOTE: credentials provider not needed for this operation telemetryProvider = telemetry logMode = attributes.getOrNull(SdkClientOption.LogMode) + applicationId = attributes.getOrNull(AwsSdkClientOption.ApplicationId) } val resp = try { diff --git a/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/AwsSdkClientOption.kt b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/AwsSdkClientOption.kt new file mode 100644 index 00000000000..0defe514643 --- /dev/null +++ b/aws-runtime/aws-config/common/src/aws/sdk/kotlin/runtime/config/AwsSdkClientOption.kt @@ -0,0 +1,20 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package aws.sdk.kotlin.runtime.config + +import aws.smithy.kotlin.runtime.collections.AttributeKey + +/** + * Common client execution options. + * AWS-specific version of [aws.smithy.kotlin.runtime.client.SdkClientOption] + */ +public object AwsSdkClientOption { + /** + * An optional application specific identifier. + * When set it will be appended to the User-Agent header of every request in the form of: `app/{applicationId}`. + */ + public val ApplicationId: AttributeKey = AttributeKey("aws.sdk.kotlin#ApplicationId") +} diff --git a/codegen/aws-sdk-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt b/codegen/aws-sdk-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt index 56364a006b2..f5a7c40846d 100644 --- a/codegen/aws-sdk-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt +++ b/codegen/aws-sdk-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsRuntimeTypes.kt @@ -38,6 +38,7 @@ object AwsRuntimeTypes { val AbstractAwsSdkClientFactory = symbol("AbstractAwsSdkClientFactory", "config") val AwsSdkClientConfig = symbol("AwsSdkClientConfig", "config") + val AwsSdkClientOption = symbol("AwsSdkClientOption", "config") object Endpoints : RuntimeTypePackage(AwsKotlinDependency.AWS_CONFIG, "config.endpoints") { val AccountIdEndpointMode = symbol("AccountIdEndpointMode") diff --git a/codegen/aws-sdk-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt b/codegen/aws-sdk-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt index 436a6a5aa8e..999bd8f53c3 100644 --- a/codegen/aws-sdk-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt +++ b/codegen/aws-sdk-codegen/src/main/kotlin/aws/sdk/kotlin/codegen/AwsServiceConfigIntegration.kt @@ -5,6 +5,7 @@ package aws.sdk.kotlin.codegen import software.amazon.smithy.kotlin.codegen.core.* +import software.amazon.smithy.kotlin.codegen.integration.AppendingSectionWriter import software.amazon.smithy.kotlin.codegen.integration.KotlinIntegration import software.amazon.smithy.kotlin.codegen.integration.SectionWriterBinding import software.amazon.smithy.kotlin.codegen.lang.KotlinTypes @@ -12,6 +13,7 @@ import software.amazon.smithy.kotlin.codegen.model.asNullable import software.amazon.smithy.kotlin.codegen.model.knowledge.AwsSignatureVersion4 import software.amazon.smithy.kotlin.codegen.model.nullable import software.amazon.smithy.kotlin.codegen.rendering.* +import software.amazon.smithy.kotlin.codegen.rendering.protocol.HttpProtocolClientGenerator import software.amazon.smithy.kotlin.codegen.rendering.util.ConfigProperty import software.amazon.smithy.kotlin.codegen.rendering.util.ConfigPropertyType import software.amazon.smithy.kotlin.codegen.rendering.util.RuntimeConfigProperty @@ -173,6 +175,12 @@ class AwsServiceConfigIntegration : KotlinIntegration { writer.getContextValue(ServiceClientGenerator.Sections.CompanionObject.ServiceSymbol), ) }, + SectionWriterBinding( + HttpProtocolClientGenerator.MergeServiceDefaults, + AppendingSectionWriter { writer -> + writer.write("ctx.#T(#T.ApplicationId, config.#L)", RuntimeTypes.Core.Collections.putIfAbsentNotNull, AwsRuntimeTypes.Config.AwsSdkClientOption, UserAgentAppId.propertyName) + }, + ), ) override fun additionalServiceConfigProps(ctx: CodegenContext): List = buildList {