From dbcfe731f35ec169c6d23ff2abd74c6c8578e6f6 Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Wed, 24 Jan 2024 20:45:11 -0600
Subject: [PATCH 01/29] Add placeholder types for S3 Express

This commit adds supporting types for S3 Express. They are provided via
the S3 customization and defining Rust types live in `aws-inlineable`.
---
 .../aws-inlineable/src/s3_express.rs          | 115 ++++++++++
 .../customize/s3/S3ExpressDecorator.kt        | 208 ++++++++++++++++++
 2 files changed, 323 insertions(+)
 create mode 100644 aws/rust-runtime/aws-inlineable/src/s3_express.rs
 create mode 100644 aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt

diff --git a/aws/rust-runtime/aws-inlineable/src/s3_express.rs b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
new file mode 100644
index 0000000000..5bff3435f4
--- /dev/null
+++ b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
@@ -0,0 +1,115 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+pub mod auth {
+    use aws_smithy_runtime_api::box_error::BoxError;
+    use aws_smithy_runtime_api::client::auth::{
+        AuthScheme, AuthSchemeEndpointConfig, AuthSchemeId, Sign,
+    };
+    use aws_smithy_runtime_api::client::identity::{Identity, SharedIdentityResolver};
+    use aws_smithy_runtime_api::client::orchestrator::HttpRequest;
+    use aws_smithy_runtime_api::client::runtime_components::{
+        GetIdentityResolver, RuntimeComponents,
+    };
+    use aws_smithy_types::config_bag::ConfigBag;
+
+    /// Auth scheme ID for S3 Express.
+    pub(crate) const SCHEME_ID: AuthSchemeId = AuthSchemeId::new("sigv4-s3express");
+
+    /// S3 Express auth scheme.
+    #[derive(Debug, Default)]
+    pub(crate) struct S3ExpressAuthScheme {
+        signer: S3ExpressSigner,
+    }
+
+    impl S3ExpressAuthScheme {
+        /// Creates a new `S3ExpressAuthScheme`.
+        pub fn new() -> Self {
+            Default::default()
+        }
+    }
+
+    impl AuthScheme for S3ExpressAuthScheme {
+        fn scheme_id(&self) -> AuthSchemeId {
+            SCHEME_ID
+        }
+
+        fn identity_resolver(
+            &self,
+            identity_resolvers: &dyn GetIdentityResolver,
+        ) -> Option<SharedIdentityResolver> {
+            identity_resolvers.identity_resolver(self.scheme_id())
+        }
+
+        fn signer(&self) -> &dyn Sign {
+            &self.signer
+        }
+    }
+
+    /// S3 Express signer.
+    #[derive(Debug, Default)]
+    pub(crate) struct S3ExpressSigner;
+
+    impl Sign for S3ExpressSigner {
+        fn sign_http_request(
+            &self,
+            _request: &mut HttpRequest,
+            _identity: &Identity,
+            _auth_scheme_endpoint_config: AuthSchemeEndpointConfig<'_>,
+            _runtime_components: &RuntimeComponents,
+            _config_bag: &ConfigBag,
+        ) -> Result<(), BoxError> {
+            todo!()
+        }
+    }
+}
+
+pub mod identity_cache {
+    /// The caching implementation for S3 Express identity.
+    ///
+    /// While customers can either disable S3 Express itself or provide a custom S3 Express identity
+    /// provider, configuring S3 Express identity cache is not supported. Thus, this is _the_
+    /// implementation of S3 Express identity cache.
+    #[derive(Debug)]
+    pub(crate) struct S3ExpressIdentityCache;
+}
+
+pub mod identity_provider {
+    use crate::s3_express::identity_cache::S3ExpressIdentityCache;
+    use aws_credential_types::provider::ProvideCredentials;
+
+    #[derive(Debug)]
+    pub(crate) struct DefaultS3ExpressIdentityProvider {
+        _cache: S3ExpressIdentityCache,
+    }
+
+    #[derive(Default)]
+    pub(crate) struct Builder;
+
+    impl DefaultS3ExpressIdentityProvider {
+        pub(crate) fn builder() -> Builder {
+            Builder
+        }
+    }
+
+    impl Builder {
+        pub(crate) fn build(self) -> DefaultS3ExpressIdentityProvider {
+            DefaultS3ExpressIdentityProvider {
+                _cache: S3ExpressIdentityCache,
+            }
+        }
+    }
+
+    impl ProvideCredentials for DefaultS3ExpressIdentityProvider {
+        fn provide_credentials<'a>(
+            &'a self,
+        ) -> aws_credential_types::provider::future::ProvideCredentials<'a>
+        where
+            Self: 'a,
+        {
+            todo!()
+        }
+    }
+}
diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
new file mode 100644
index 0000000000..f983c55da7
--- /dev/null
+++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
@@ -0,0 +1,208 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package software.amazon.smithy.rustsdk.customize.s3
+
+import software.amazon.smithy.aws.traits.auth.SigV4Trait
+import software.amazon.smithy.model.shapes.OperationShape
+import software.amazon.smithy.model.shapes.ShapeId
+import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
+import software.amazon.smithy.rust.codegen.client.smithy.configReexport
+import software.amazon.smithy.rust.codegen.client.smithy.customize.AuthSchemeOption
+import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator
+import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginCustomization
+import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginSection
+import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization
+import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig
+import software.amazon.smithy.rust.codegen.core.rustlang.Writable
+import software.amazon.smithy.rust.codegen.core.rustlang.rust
+import software.amazon.smithy.rust.codegen.core.rustlang.rustBlockTemplate
+import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
+import software.amazon.smithy.rust.codegen.core.rustlang.writable
+import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
+import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope
+import software.amazon.smithy.rustsdk.AwsRuntimeType
+import software.amazon.smithy.rustsdk.InlineAwsDependency
+
+class S3ExpressDecorator : ClientCodegenDecorator {
+    override val name: String = "S3ExpressDecorator"
+    override val order: Byte = 0
+
+    private fun sigv4S3Express() = writable {
+        rust(
+            "#T",
+            RuntimeType.forInlineDependency(
+                InlineAwsDependency.forRustFile("s3_express"),
+            ).resolve("auth::SCHEME_ID"),
+        )
+    }
+
+    override fun authOptions(
+        codegenContext: ClientCodegenContext,
+        operationShape: OperationShape,
+        baseAuthSchemeOptions: List<AuthSchemeOption>,
+    ): List<AuthSchemeOption> =
+        baseAuthSchemeOptions +
+            AuthSchemeOption.StaticAuthSchemeOption(
+                SigV4Trait.ID,
+                listOf(sigv4S3Express()),
+            )
+
+    override fun serviceRuntimePluginCustomizations(
+        codegenContext: ClientCodegenContext,
+        baseCustomizations: List<ServiceRuntimePluginCustomization>,
+    ): List<ServiceRuntimePluginCustomization> =
+        baseCustomizations + listOf(S3ExpressServiceRuntimePluginCustomization(codegenContext))
+
+    override fun configCustomizations(
+        codegenContext: ClientCodegenContext,
+        baseCustomizations: List<ConfigCustomization>,
+    ): List<ConfigCustomization> =
+        baseCustomizations + listOf(S3ExpressIdentityProviderConfig(codegenContext))
+}
+
+private class S3ExpressServiceRuntimePluginCustomization(codegenContext: ClientCodegenContext) :
+    ServiceRuntimePluginCustomization() {
+    private val runtimeConfig = codegenContext.runtimeConfig
+    private val codegenScope by lazy {
+        arrayOf(
+            "DefaultS3ExpressIdentityProvider" to
+                RuntimeType.forInlineDependency(
+                    InlineAwsDependency.forRustFile("s3_express"),
+                ).resolve("identity_provider::DefaultS3ExpressIdentityProvider"),
+            "IdentityCacheLocation" to
+                RuntimeType.smithyRuntimeApiClient(runtimeConfig)
+                    .resolve("client::identity::IdentityCacheLocation"),
+            "S3ExpressAuthScheme" to
+                RuntimeType.forInlineDependency(
+                    InlineAwsDependency.forRustFile("s3_express"),
+                ).resolve("auth::S3ExpressAuthScheme"),
+            "S3_EXPRESS_SCHEME_ID" to
+                RuntimeType.forInlineDependency(
+                    InlineAwsDependency.forRustFile("s3_express"),
+                ).resolve("auth::SCHEME_ID"),
+            "SharedAuthScheme" to RuntimeType.smithyRuntimeApiClient(runtimeConfig)
+                .resolve("client::auth::SharedAuthScheme"),
+            "SharedCredentialsProvider" to
+                configReexport(
+                    AwsRuntimeType.awsCredentialTypes(runtimeConfig)
+                        .resolve("provider::SharedCredentialsProvider"),
+                ),
+            "SharedIdentityResolver" to RuntimeType.smithyRuntimeApiClient(runtimeConfig)
+                .resolve("client::identity::SharedIdentityResolver"),
+        )
+    }
+
+    override fun section(section: ServiceRuntimePluginSection): Writable =
+        writable {
+            when (section) {
+                is ServiceRuntimePluginSection.RegisterRuntimeComponents -> {
+                    section.registerAuthScheme(this) {
+                        rustTemplate(
+                            "#{SharedAuthScheme}::new(#{S3ExpressAuthScheme}::new())",
+                            *codegenScope,
+                        )
+                    }
+
+                    section.registerSharedIdentityResolver(
+                        this,
+                        writable {
+                            rustTemplate("#{S3_EXPRESS_SCHEME_ID}", *codegenScope)
+                        },
+                        writable {
+                            rustTemplate(
+                                """
+                                    #{SharedIdentityResolver}::new_with_cache_location(
+                                            #{SharedCredentialsProvider}::new(
+                                                #{DefaultS3ExpressIdentityProvider}::builder().build()
+                                            ),
+                                            #{IdentityCacheLocation}::IdentityResolver,
+                                    )
+                                    """,
+                                *codegenScope,
+                            )
+                        },
+                    )
+                }
+
+                else -> {}
+            }
+        }
+}
+
+class S3ExpressIdentityProviderConfig(codegenContext: ClientCodegenContext) : ConfigCustomization() {
+    private val runtimeConfig = codegenContext.runtimeConfig
+    private val codegenScope =
+        arrayOf(
+            *preludeScope,
+            "IdentityCacheLocation" to
+                RuntimeType.smithyRuntimeApiClient(runtimeConfig)
+                    .resolve("client::identity::IdentityCacheLocation"),
+            "ProvideCredentials" to
+                configReexport(
+                    AwsRuntimeType.awsCredentialTypes(runtimeConfig)
+                        .resolve("provider::ProvideCredentials"),
+                ),
+            "SharedCredentialsProvider" to
+                configReexport(
+                    AwsRuntimeType.awsCredentialTypes(runtimeConfig)
+                        .resolve("provider::SharedCredentialsProvider"),
+                ),
+            "SharedIdentityResolver" to RuntimeType.smithyRuntimeApiClient(runtimeConfig)
+                .resolve("client::identity::SharedIdentityResolver"),
+            "S3_EXPRESS_SCHEME_ID" to
+                RuntimeType.forInlineDependency(
+                    InlineAwsDependency.forRustFile("s3_express"),
+                ).resolve("auth::SCHEME_ID"),
+        )
+
+    override fun section(section: ServiceConfig) =
+        writable {
+            when (section) {
+                ServiceConfig.BuilderImpl -> {
+                    rustTemplate(
+                        """
+                        /// Sets the credentials provider for S3 Express
+                        pub fn express_credentials_provider(mut self, credentials_provider: impl #{ProvideCredentials} + 'static) -> Self {
+                            self.set_express_credentials_provider(#{Some}(#{SharedCredentialsProvider}::new(credentials_provider)));
+                            self
+                        }
+                        """,
+                        *codegenScope,
+                    )
+
+                    rustBlockTemplate(
+                        """
+                        /// Sets the credentials provider for S3 Express
+                        pub fn set_express_credentials_provider(&mut self, credentials_provider: #{Option}<#{SharedCredentialsProvider}>) -> &mut Self
+                        """,
+                        *codegenScope,
+                    ) {
+                        rustBlockTemplate(
+                            """
+                            if let #{Some}(credentials_provider) = credentials_provider
+                            """,
+                            *codegenScope,
+                        ) {
+                            rustTemplate(
+                                """
+                                    self.runtime_components.set_shared_identity_resolver(
+                                        #{S3_EXPRESS_SCHEME_ID},
+                                        #{SharedIdentityResolver}::new_with_cache_location(
+                                            credentials_provider,
+                                            #{IdentityCacheLocation}::IdentityResolver),
+                                    );
+                                    """,
+                                *codegenScope,
+                            )
+                        }
+                        rust("self")
+                    }
+                }
+
+                else -> emptySection
+            }
+        }
+}

From 714aaad3a9aaaa4bee4a57ffccfcbd8f77954ec4 Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Wed, 24 Jan 2024 20:45:44 -0600
Subject: [PATCH 02/29] Enable control flow to be altered for S3 Express

This commit updates parts of the orchestrator so that when an S3 Express
bucket name is passed, control flow will be directed to placeholder types
added in the previous commit.
---
 aws/rust-runtime/aws-inlineable/src/lib.rs    |  4 +++
 .../smithy/rustsdk/AwsCodegenDecorator.kt     |  2 ++
 .../ServiceRuntimePluginGenerator.kt          |  8 +++++
 .../src/client/identity.rs                    | 31 +++++++++++++++++++
 .../src/client/runtime_components.rs          | 14 ++++++++-
 .../src/client/orchestrator/auth.rs           | 11 +++++--
 6 files changed, 67 insertions(+), 3 deletions(-)

diff --git a/aws/rust-runtime/aws-inlineable/src/lib.rs b/aws/rust-runtime/aws-inlineable/src/lib.rs
index 0ae9627703..91811be46a 100644
--- a/aws/rust-runtime/aws-inlineable/src/lib.rs
+++ b/aws/rust-runtime/aws-inlineable/src/lib.rs
@@ -31,6 +31,10 @@ pub mod presigning;
 /// Presigning interceptors
 pub mod presigning_interceptors;
 
+/// Supporting types for S3 Express.
+#[allow(dead_code)]
+pub mod s3_express;
+
 /// Special logic for extracting request IDs from S3's responses.
 #[allow(dead_code)]
 pub mod s3_request_id;
diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt
index 3bc616a9b8..2c13e4b2b7 100644
--- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt
+++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt
@@ -18,6 +18,7 @@ import software.amazon.smithy.rustsdk.customize.glacier.GlacierDecorator
 import software.amazon.smithy.rustsdk.customize.onlyApplyTo
 import software.amazon.smithy.rustsdk.customize.route53.Route53Decorator
 import software.amazon.smithy.rustsdk.customize.s3.S3Decorator
+import software.amazon.smithy.rustsdk.customize.s3.S3ExpressDecorator
 import software.amazon.smithy.rustsdk.customize.s3.S3ExtendedRequestIdDecorator
 import software.amazon.smithy.rustsdk.customize.s3control.S3ControlDecorator
 import software.amazon.smithy.rustsdk.customize.sso.SSODecorator
@@ -64,6 +65,7 @@ val DECORATORS: List<ClientCodegenDecorator> =
         Route53Decorator().onlyApplyTo("com.amazonaws.route53#AWSDnsV20130401"),
         "com.amazonaws.s3#AmazonS3".applyDecorators(
             S3Decorator(),
+            S3ExpressDecorator(),
             S3ExtendedRequestIdDecorator(),
         ),
         S3ControlDecorator().onlyApplyTo("com.amazonaws.s3control#AWSS3ControlServiceV20180820"),
diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt
index 66095c1555..1d58b732c6 100644
--- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt
+++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt
@@ -69,6 +69,14 @@ sealed class ServiceRuntimePluginSection(name: String) : Section(name) {
         ) {
             writer.rust("runtime_components.push_retry_classifier(#T);", classifier)
         }
+
+        fun registerSharedIdentityResolver(
+            writer: RustWriter,
+            schemeId: Writable,
+            identityResolver: Writable,
+        ) {
+            writer.rust("runtime_components.set_shared_identity_resolver(#T, #T);", schemeId, identityResolver)
+        }
     }
 }
 typealias ServiceRuntimePluginCustomization = NamedCustomization<ServiceRuntimePluginSection>
diff --git a/rust-runtime/aws-smithy-runtime-api/src/client/identity.rs b/rust-runtime/aws-smithy-runtime-api/src/client/identity.rs
index f0e972675a..acfd960020 100644
--- a/rust-runtime/aws-smithy-runtime-api/src/client/identity.rs
+++ b/rust-runtime/aws-smithy-runtime-api/src/client/identity.rs
@@ -161,19 +161,45 @@ pub trait ResolveIdentity: Send + Sync + Debug {
     }
 }
 
+/// Cache location for identity caching.
+///
+/// Identities are usually cached in the identity cache owned by [`RuntimeComponents`]. However,
+/// we do have identities whose caching mechanism is internally managed by their identity resolver,
+/// in which case we want to avoid the `RuntimeComponents`-owned identity cache interfering with
+/// the internal caching policy.
+#[non_exhaustive]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum IdentityCacheLocation {
+    /// Indicates the identity cache is owned by [`RuntimeComponents`].
+    RuntimeComponents,
+    /// Indicates the identity cache is internally managed by the identity resolver.
+    IdentityResolver,
+}
+
 /// Container for a shared identity resolver.
 #[derive(Clone, Debug)]
 pub struct SharedIdentityResolver {
     inner: Arc<dyn ResolveIdentity>,
     cache_partition: IdentityCachePartition,
+    cache_location: IdentityCacheLocation,
 }
 
 impl SharedIdentityResolver {
     /// Creates a new [`SharedIdentityResolver`] from the given resolver.
     pub fn new(resolver: impl ResolveIdentity + 'static) -> Self {
+        Self::new_with_cache_location(resolver, IdentityCacheLocation::RuntimeComponents)
+    }
+
+    /// Creates a new [`SharedIdentityResolver`] from the given resolver with the additional argument
+    /// specifying where the identity cache location is.
+    pub fn new_with_cache_location(
+        resolver: impl ResolveIdentity + 'static,
+        cache_location: IdentityCacheLocation,
+    ) -> Self {
         Self {
             inner: Arc::new(resolver),
             cache_partition: IdentityCachePartition::new(),
+            cache_location,
         }
     }
 
@@ -184,6 +210,11 @@ impl SharedIdentityResolver {
     pub fn cache_partition(&self) -> IdentityCachePartition {
         self.cache_partition
     }
+
+    /// Returns where identities retrieved by this resolver are cached.
+    pub fn cache_location(&self) -> IdentityCacheLocation {
+        self.cache_location
+    }
 }
 
 impl ResolveIdentity for SharedIdentityResolver {
diff --git a/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs b/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs
index dc9f65d56a..d9cade9d1e 100644
--- a/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs
+++ b/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs
@@ -612,11 +612,23 @@ impl RuntimeComponentsBuilder {
         &mut self,
         scheme_id: AuthSchemeId,
         identity_resolver: impl ResolveIdentity + 'static,
+    ) -> &mut Self {
+        self.set_shared_identity_resolver(scheme_id, identity_resolver.into_shared())
+    }
+
+    /// Sets the identity resolver for a given `scheme_id`.
+    ///
+    /// This is effectively the same as [`Self::set_identity_resolver`] but takes a [`SharedIdentityResolver`]
+    /// instead.
+    pub fn set_shared_identity_resolver(
+        &mut self,
+        scheme_id: AuthSchemeId,
+        shared_identity_resolver: SharedIdentityResolver,
     ) -> &mut Self {
         let mut resolvers = self.identity_resolvers.take().unwrap_or_default();
         resolvers.insert(
             scheme_id,
-            Tracked::new(self.builder_name, identity_resolver.into_shared()),
+            Tracked::new(self.builder_name, shared_identity_resolver),
         );
         self.identity_resolvers = Some(resolvers);
         self
diff --git a/rust-runtime/aws-smithy-runtime/src/client/orchestrator/auth.rs b/rust-runtime/aws-smithy-runtime/src/client/orchestrator/auth.rs
index 98a39a9a43..ccca10bf34 100644
--- a/rust-runtime/aws-smithy-runtime/src/client/orchestrator/auth.rs
+++ b/rust-runtime/aws-smithy-runtime/src/client/orchestrator/auth.rs
@@ -4,12 +4,13 @@
  */
 
 use crate::client::auth::no_auth::NO_AUTH_SCHEME_ID;
+use crate::client::identity::IdentityCache;
 use aws_smithy_runtime_api::box_error::BoxError;
 use aws_smithy_runtime_api::client::auth::{
     AuthScheme, AuthSchemeEndpointConfig, AuthSchemeId, AuthSchemeOptionResolverParams,
     ResolveAuthSchemeOptions,
 };
-use aws_smithy_runtime_api::client::identity::ResolveCachedIdentity;
+use aws_smithy_runtime_api::client::identity::{IdentityCacheLocation, ResolveCachedIdentity};
 use aws_smithy_runtime_api::client::interceptors::context::InterceptorContext;
 use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;
 use aws_smithy_types::config_bag::ConfigBag;
@@ -135,7 +136,13 @@ pub(super) async fn orchestrate_auth(
         if let Some(auth_scheme) = runtime_components.auth_scheme(scheme_id) {
             // Use the resolved auth scheme to resolve an identity
             if let Some(identity_resolver) = auth_scheme.identity_resolver(runtime_components) {
-                let identity_cache = runtime_components.identity_cache();
+                let identity_cache = if identity_resolver.cache_location()
+                    == IdentityCacheLocation::RuntimeComponents
+                {
+                    runtime_components.identity_cache()
+                } else {
+                    IdentityCache::no_cache()
+                };
                 let signer = auth_scheme.signer();
                 trace!(
                     auth_scheme = ?auth_scheme,

From 9086db29992b87d9d5a94ff4564a0356b1737639 Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Thu, 25 Jan 2024 10:58:57 -0600
Subject: [PATCH 03/29] Fix lint-related failures in CI

---
 .../aws-inlineable/src/s3_express.rs          |  5 +-
 .../customize/s3/S3ExpressDecorator.kt        | 64 ++++++++++---------
 2 files changed, 37 insertions(+), 32 deletions(-)

diff --git a/aws/rust-runtime/aws-inlineable/src/s3_express.rs b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
index 5bff3435f4..4eaef984b0 100644
--- a/aws/rust-runtime/aws-inlineable/src/s3_express.rs
+++ b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
@@ -3,6 +3,7 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
+/// Supporting code for S3 Express auth
 pub mod auth {
     use aws_smithy_runtime_api::box_error::BoxError;
     use aws_smithy_runtime_api::client::auth::{
@@ -26,7 +27,7 @@ pub mod auth {
 
     impl S3ExpressAuthScheme {
         /// Creates a new `S3ExpressAuthScheme`.
-        pub fn new() -> Self {
+        pub(crate) fn new() -> Self {
             Default::default()
         }
     }
@@ -66,6 +67,7 @@ pub mod auth {
     }
 }
 
+/// Supporting code for S3 Express identity cache
 pub mod identity_cache {
     /// The caching implementation for S3 Express identity.
     ///
@@ -76,6 +78,7 @@ pub mod identity_cache {
     pub(crate) struct S3ExpressIdentityCache;
 }
 
+/// Supporting code for S3 Express identity provider
 pub mod identity_provider {
     use crate::s3_express::identity_cache::S3ExpressIdentityCache;
     use aws_credential_types::provider::ProvideCredentials;
diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
index f983c55da7..62f6ce7bfd 100644
--- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
+++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
@@ -7,7 +7,6 @@ package software.amazon.smithy.rustsdk.customize.s3
 
 import software.amazon.smithy.aws.traits.auth.SigV4Trait
 import software.amazon.smithy.model.shapes.OperationShape
-import software.amazon.smithy.model.shapes.ShapeId
 import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
 import software.amazon.smithy.rust.codegen.client.smithy.configReexport
 import software.amazon.smithy.rust.codegen.client.smithy.customize.AuthSchemeOption
@@ -30,14 +29,15 @@ class S3ExpressDecorator : ClientCodegenDecorator {
     override val name: String = "S3ExpressDecorator"
     override val order: Byte = 0
 
-    private fun sigv4S3Express() = writable {
-        rust(
-            "#T",
-            RuntimeType.forInlineDependency(
-                InlineAwsDependency.forRustFile("s3_express"),
-            ).resolve("auth::SCHEME_ID"),
-        )
-    }
+    private fun sigv4S3Express() =
+        writable {
+            rust(
+                "#T",
+                RuntimeType.forInlineDependency(
+                    InlineAwsDependency.forRustFile("s3_express"),
+                ).resolve("auth::SCHEME_ID"),
+            )
+        }
 
     override fun authOptions(
         codegenContext: ClientCodegenContext,
@@ -59,8 +59,7 @@ class S3ExpressDecorator : ClientCodegenDecorator {
     override fun configCustomizations(
         codegenContext: ClientCodegenContext,
         baseCustomizations: List<ConfigCustomization>,
-    ): List<ConfigCustomization> =
-        baseCustomizations + listOf(S3ExpressIdentityProviderConfig(codegenContext))
+    ): List<ConfigCustomization> = baseCustomizations + listOf(S3ExpressIdentityProviderConfig(codegenContext))
 }
 
 private class S3ExpressServiceRuntimePluginCustomization(codegenContext: ClientCodegenContext) :
@@ -83,15 +82,17 @@ private class S3ExpressServiceRuntimePluginCustomization(codegenContext: ClientC
                 RuntimeType.forInlineDependency(
                     InlineAwsDependency.forRustFile("s3_express"),
                 ).resolve("auth::SCHEME_ID"),
-            "SharedAuthScheme" to RuntimeType.smithyRuntimeApiClient(runtimeConfig)
-                .resolve("client::auth::SharedAuthScheme"),
+            "SharedAuthScheme" to
+                RuntimeType.smithyRuntimeApiClient(runtimeConfig)
+                    .resolve("client::auth::SharedAuthScheme"),
             "SharedCredentialsProvider" to
                 configReexport(
                     AwsRuntimeType.awsCredentialTypes(runtimeConfig)
                         .resolve("provider::SharedCredentialsProvider"),
                 ),
-            "SharedIdentityResolver" to RuntimeType.smithyRuntimeApiClient(runtimeConfig)
-                .resolve("client::identity::SharedIdentityResolver"),
+            "SharedIdentityResolver" to
+                RuntimeType.smithyRuntimeApiClient(runtimeConfig)
+                    .resolve("client::identity::SharedIdentityResolver"),
         )
     }
 
@@ -114,13 +115,13 @@ private class S3ExpressServiceRuntimePluginCustomization(codegenContext: ClientC
                         writable {
                             rustTemplate(
                                 """
-                                    #{SharedIdentityResolver}::new_with_cache_location(
-                                            #{SharedCredentialsProvider}::new(
-                                                #{DefaultS3ExpressIdentityProvider}::builder().build()
-                                            ),
-                                            #{IdentityCacheLocation}::IdentityResolver,
-                                    )
-                                    """,
+                                #{SharedIdentityResolver}::new_with_cache_location(
+                                        #{SharedCredentialsProvider}::new(
+                                            #{DefaultS3ExpressIdentityProvider}::builder().build()
+                                        ),
+                                        #{IdentityCacheLocation}::IdentityResolver,
+                                )
+                                """,
                                 *codegenScope,
                             )
                         },
@@ -150,8 +151,9 @@ class S3ExpressIdentityProviderConfig(codegenContext: ClientCodegenContext) : Co
                     AwsRuntimeType.awsCredentialTypes(runtimeConfig)
                         .resolve("provider::SharedCredentialsProvider"),
                 ),
-            "SharedIdentityResolver" to RuntimeType.smithyRuntimeApiClient(runtimeConfig)
-                .resolve("client::identity::SharedIdentityResolver"),
+            "SharedIdentityResolver" to
+                RuntimeType.smithyRuntimeApiClient(runtimeConfig)
+                    .resolve("client::identity::SharedIdentityResolver"),
             "S3_EXPRESS_SCHEME_ID" to
                 RuntimeType.forInlineDependency(
                     InlineAwsDependency.forRustFile("s3_express"),
@@ -188,13 +190,13 @@ class S3ExpressIdentityProviderConfig(codegenContext: ClientCodegenContext) : Co
                         ) {
                             rustTemplate(
                                 """
-                                    self.runtime_components.set_shared_identity_resolver(
-                                        #{S3_EXPRESS_SCHEME_ID},
-                                        #{SharedIdentityResolver}::new_with_cache_location(
-                                            credentials_provider,
-                                            #{IdentityCacheLocation}::IdentityResolver),
-                                    );
-                                    """,
+                                self.runtime_components.set_shared_identity_resolver(
+                                    #{S3_EXPRESS_SCHEME_ID},
+                                    #{SharedIdentityResolver}::new_with_cache_location(
+                                        credentials_provider,
+                                        #{IdentityCacheLocation}::IdentityResolver),
+                                );
+                                """,
                                 *codegenScope,
                             )
                         }

From 1f07f92422ea476dba0d65be868abf1ae917635c Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Thu, 25 Jan 2024 11:36:58 -0600
Subject: [PATCH 04/29] Temporarily disable S3 Express endpoint tests

---
 .../rustsdk/endpoints/OperationInputTestGenerator.kt      | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/OperationInputTestGenerator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/OperationInputTestGenerator.kt
index 5bcc870ae5..544d30ea8f 100644
--- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/OperationInputTestGenerator.kt
+++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/OperationInputTestGenerator.kt
@@ -126,9 +126,17 @@ class OperationInputTestGenerator(_ctx: ClientCodegenContext, private val test:
     private val model = ctx.model
     private val instantiator = ClientInstantiator(ctx)
 
+    /** tests using S3 Express bucket names need to be disabled until the implementation is in place **/
+    private fun EndpointTestCase.isSigV4S3Express() =
+        expect.endpoint.orNull()?.properties?.get("authSchemes")?.asArrayNode()?.orNull()
+            ?.map { it.expectObjectNode().expectStringMember("name").value }?.contains("sigv4-s3express") == true
+
     fun generateInput(testOperationInput: EndpointTestOperationInput) =
         writable {
             val operationName = testOperationInput.operationName.toSnakeCase()
+            if (test.isSigV4S3Express()) {
+                Attribute.shouldPanic("not yet implemented").render(this)
+            }
             tokioTest(safeName("operation_input_test_$operationName")) {
                 rustTemplate(
                     """

From 13c3c5ad2508568524e815137e32df2a4d64baf9 Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Mon, 29 Jan 2024 10:53:36 -0600
Subject: [PATCH 05/29] Update
 aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt

Co-authored-by: John DiSanti <jdisanti@amazon.com>
---
 .../amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
index 62f6ce7bfd..a5d9605de4 100644
--- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
+++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
@@ -166,7 +166,7 @@ class S3ExpressIdentityProviderConfig(codegenContext: ClientCodegenContext) : Co
                 ServiceConfig.BuilderImpl -> {
                     rustTemplate(
                         """
-                        /// Sets the credentials provider for S3 Express
+                        /// Sets the credentials provider for S3 Express One Zone
                         pub fn express_credentials_provider(mut self, credentials_provider: impl #{ProvideCredentials} + 'static) -> Self {
                             self.set_express_credentials_provider(#{Some}(#{SharedCredentialsProvider}::new(credentials_provider)));
                             self

From 38ce80fa2c99ebb87fdb7b93d4909f9fb3788af0 Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Mon, 29 Jan 2024 10:44:34 -0600
Subject: [PATCH 06/29] Make s3_express inlineable modules `pub(crate)`

This commit addresses https://github.com/smithy-lang/smithy-rs/pull/3386#discussion_r1467050694
---
 aws/rust-runtime/aws-inlineable/src/s3_express.rs | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/aws/rust-runtime/aws-inlineable/src/s3_express.rs b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
index 4eaef984b0..e7a9dfd08b 100644
--- a/aws/rust-runtime/aws-inlineable/src/s3_express.rs
+++ b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
@@ -4,7 +4,7 @@
  */
 
 /// Supporting code for S3 Express auth
-pub mod auth {
+pub(crate) mod auth {
     use aws_smithy_runtime_api::box_error::BoxError;
     use aws_smithy_runtime_api::client::auth::{
         AuthScheme, AuthSchemeEndpointConfig, AuthSchemeId, Sign,
@@ -68,7 +68,7 @@ pub mod auth {
 }
 
 /// Supporting code for S3 Express identity cache
-pub mod identity_cache {
+pub(crate) mod identity_cache {
     /// The caching implementation for S3 Express identity.
     ///
     /// While customers can either disable S3 Express itself or provide a custom S3 Express identity
@@ -79,7 +79,7 @@ pub mod identity_cache {
 }
 
 /// Supporting code for S3 Express identity provider
-pub mod identity_provider {
+pub(crate) mod identity_provider {
     use crate::s3_express::identity_cache::S3ExpressIdentityCache;
     use aws_credential_types::provider::ProvideCredentials;
 

From ef1e1be139966ac5b8c14d60f1d0342045fb9b77 Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Mon, 29 Jan 2024 11:47:17 -0600
Subject: [PATCH 07/29] Remove unnecessary `set_shared_identity_resolver`

This commit addresses https://github.com/smithy-lang/smithy-rs/pull/3386#discussion_r1467053587
---
 .../rustsdk/customize/s3/S3ExpressDecorator.kt     |  4 ++--
 .../generators/ServiceRuntimePluginGenerator.kt    |  4 ++--
 .../src/client/runtime_components.rs               | 14 +-------------
 3 files changed, 5 insertions(+), 17 deletions(-)

diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
index a5d9605de4..f12bec3e2d 100644
--- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
+++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
@@ -107,7 +107,7 @@ private class S3ExpressServiceRuntimePluginCustomization(codegenContext: ClientC
                         )
                     }
 
-                    section.registerSharedIdentityResolver(
+                    section.registerIdentityResolver(
                         this,
                         writable {
                             rustTemplate("#{S3_EXPRESS_SCHEME_ID}", *codegenScope)
@@ -190,7 +190,7 @@ class S3ExpressIdentityProviderConfig(codegenContext: ClientCodegenContext) : Co
                         ) {
                             rustTemplate(
                                 """
-                                self.runtime_components.set_shared_identity_resolver(
+                                self.runtime_components.set_identity_resolver(
                                     #{S3_EXPRESS_SCHEME_ID},
                                     #{SharedIdentityResolver}::new_with_cache_location(
                                         credentials_provider,
diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt
index 1d58b732c6..699e5bff19 100644
--- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt
+++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt
@@ -70,12 +70,12 @@ sealed class ServiceRuntimePluginSection(name: String) : Section(name) {
             writer.rust("runtime_components.push_retry_classifier(#T);", classifier)
         }
 
-        fun registerSharedIdentityResolver(
+        fun registerIdentityResolver(
             writer: RustWriter,
             schemeId: Writable,
             identityResolver: Writable,
         ) {
-            writer.rust("runtime_components.set_shared_identity_resolver(#T, #T);", schemeId, identityResolver)
+            writer.rust("runtime_components.set_identity_resolver(#T, #T);", schemeId, identityResolver)
         }
     }
 }
diff --git a/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs b/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs
index d9cade9d1e..dc9f65d56a 100644
--- a/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs
+++ b/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs
@@ -612,23 +612,11 @@ impl RuntimeComponentsBuilder {
         &mut self,
         scheme_id: AuthSchemeId,
         identity_resolver: impl ResolveIdentity + 'static,
-    ) -> &mut Self {
-        self.set_shared_identity_resolver(scheme_id, identity_resolver.into_shared())
-    }
-
-    /// Sets the identity resolver for a given `scheme_id`.
-    ///
-    /// This is effectively the same as [`Self::set_identity_resolver`] but takes a [`SharedIdentityResolver`]
-    /// instead.
-    pub fn set_shared_identity_resolver(
-        &mut self,
-        scheme_id: AuthSchemeId,
-        shared_identity_resolver: SharedIdentityResolver,
     ) -> &mut Self {
         let mut resolvers = self.identity_resolvers.take().unwrap_or_default();
         resolvers.insert(
             scheme_id,
-            Tracked::new(self.builder_name, shared_identity_resolver),
+            Tracked::new(self.builder_name, identity_resolver.into_shared()),
         );
         self.identity_resolvers = Some(resolvers);
         self

From 9e4542b43565ee93a9f76c5f423f7c6de51b93e2 Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Mon, 29 Jan 2024 16:30:04 -0600
Subject: [PATCH 08/29] Allow list-objects-v2 to run against S3 Express bucket

---
 .../aws-inlineable/src/s3_express.rs          | 156 ++++++++++++++++--
 .../aws-runtime/src/auth/sigv4.rs             |  60 +++++--
 .../aws-sigv4/src/http_request/sign.rs        |  23 ++-
 .../rustsdk/customize/s3/S3Decorator.kt       |   1 +
 .../customize/s3/S3ExpressDecorator.kt        |   9 +-
 .../src/client/runtime_components.rs          |  25 +++
 6 files changed, 229 insertions(+), 45 deletions(-)

diff --git a/aws/rust-runtime/aws-inlineable/src/s3_express.rs b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
index e7a9dfd08b..128573ca13 100644
--- a/aws/rust-runtime/aws-inlineable/src/s3_express.rs
+++ b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
@@ -5,6 +5,10 @@
 
 /// Supporting code for S3 Express auth
 pub(crate) mod auth {
+    use std::borrow::Cow;
+
+    use aws_credential_types::Credentials;
+    use aws_runtime::auth::sigv4::SigV4Signer;
     use aws_smithy_runtime_api::box_error::BoxError;
     use aws_smithy_runtime_api::client::auth::{
         AuthScheme, AuthSchemeEndpointConfig, AuthSchemeId, Sign,
@@ -56,13 +60,43 @@ pub(crate) mod auth {
     impl Sign for S3ExpressSigner {
         fn sign_http_request(
             &self,
-            _request: &mut HttpRequest,
-            _identity: &Identity,
-            _auth_scheme_endpoint_config: AuthSchemeEndpointConfig<'_>,
-            _runtime_components: &RuntimeComponents,
-            _config_bag: &ConfigBag,
+            request: &mut HttpRequest,
+            identity: &Identity,
+            auth_scheme_endpoint_config: AuthSchemeEndpointConfig<'_>,
+            runtime_components: &RuntimeComponents,
+            config_bag: &ConfigBag,
         ) -> Result<(), BoxError> {
-            todo!()
+            let operation_config =
+                SigV4Signer::extract_operation_config(auth_scheme_endpoint_config, config_bag)?;
+
+            let mut settings = SigV4Signer::signing_settings(&operation_config);
+            if let Some(excluded) = settings.excluded_headers.as_mut() {
+                excluded.push(Cow::Borrowed("x-amz-security-token"));
+            }
+
+            let express_credentials = identity.data::<Credentials>().ok_or(
+                "wrong identity type for SigV4. Expected AWS credentials but got `{identity:?}",
+            )?;
+            let mut value = http::HeaderValue::from_str(
+                express_credentials
+                    .session_token()
+                    .expect("S3 session token should be set"),
+            )
+            .unwrap();
+            value.set_sensitive(true);
+            request.headers_mut().insert(
+                http::HeaderName::from_static("x-amz-s3session-token"),
+                value,
+            );
+
+            SigV4Signer.sign_http_request(
+                request,
+                identity,
+                settings,
+                &operation_config,
+                runtime_components,
+                config_bag,
+            )
         }
     }
 }
@@ -80,8 +114,22 @@ pub(crate) mod identity_cache {
 
 /// Supporting code for S3 Express identity provider
 pub(crate) mod identity_provider {
+    use std::time::SystemTime;
+
     use crate::s3_express::identity_cache::S3ExpressIdentityCache;
-    use aws_credential_types::provider::ProvideCredentials;
+    use crate::types::SessionCredentials;
+    use aws_credential_types::provider::error::CredentialsError;
+    use aws_credential_types::Credentials;
+    use aws_smithy_runtime_api::box_error::BoxError;
+    use aws_smithy_runtime_api::client::endpoint::EndpointResolverParams;
+    use aws_smithy_runtime_api::client::identity::{
+        Identity, IdentityFuture, ResolveCachedIdentity, ResolveIdentity,
+    };
+    use aws_smithy_runtime_api::client::interceptors::SharedInterceptor;
+    use aws_smithy_runtime_api::client::runtime_components::{
+        GetIdentityResolver, RuntimeComponents,
+    };
+    use aws_smithy_types::config_bag::ConfigBag;
 
     #[derive(Debug)]
     pub(crate) struct DefaultS3ExpressIdentityProvider {
@@ -91,10 +139,91 @@ pub(crate) mod identity_provider {
     #[derive(Default)]
     pub(crate) struct Builder;
 
+    impl TryFrom<SessionCredentials> for Credentials {
+        type Error = BoxError;
+
+        fn try_from(session_creds: SessionCredentials) -> Result<Self, Self::Error> {
+            Ok(Credentials::new(
+                session_creds.access_key_id,
+                session_creds.secret_access_key,
+                Some(session_creds.session_token),
+                Some(SystemTime::try_from(session_creds.expiration).map_err(|_| {
+                    CredentialsError::unhandled(
+                        "credential expiration time cannot be represented by a SystemTime",
+                    )
+                })?),
+                "s3express",
+            ))
+        }
+    }
+
     impl DefaultS3ExpressIdentityProvider {
         pub(crate) fn builder() -> Builder {
             Builder
         }
+
+        async fn identity<'a>(
+            &'a self,
+            runtime_components: &'a RuntimeComponents,
+            config_bag: &'a ConfigBag,
+        ) -> Result<Identity, BoxError> {
+            let bucket_name = self.bucket_name(config_bag);
+
+            let sigv4_identity_resolver = runtime_components
+                .identity_resolver(aws_runtime::auth::sigv4::SCHEME_ID)
+                .ok_or("identity resolver for sigv4 should be set for S3")?;
+            let _aws_identity = runtime_components
+                .identity_cache()
+                .resolve_cached_identity(sigv4_identity_resolver, runtime_components, config_bag)
+                .await?;
+
+            // TODO(S3Express): use both `bucket_name` and `aws_identity` as part of `S3ExpressIdentityCache` implementation
+
+            let express_session_credentials = self
+                .express_session_credentials(bucket_name, runtime_components, config_bag)
+                .await?;
+
+            let data = Credentials::try_from(express_session_credentials)?;
+
+            Ok(Identity::new(data.clone(), data.expiry()))
+        }
+
+        fn bucket_name<'a>(&'a self, config_bag: &'a ConfigBag) -> &'a str {
+            let params = config_bag
+                .load::<EndpointResolverParams>()
+                .expect("endpoint resolver params must be set");
+            let params = params
+                .get::<crate::config::endpoint::Params>()
+                .expect("`Params` should be wrapped in `EndpointResolverParams`");
+            params.bucket().expect("bucket name must be set")
+        }
+
+        async fn express_session_credentials<'a>(
+            &'a self,
+            bucket_name: &'a str,
+            runtime_components: &'a RuntimeComponents,
+            config_bag: &'a ConfigBag,
+        ) -> Result<SessionCredentials, BoxError> {
+            let mut config_builder = crate::Config::builder()
+                .region(config_bag.load::<aws_types::region::Region>().cloned());
+            // inherits all runtime components from a current S3 operation but clears out
+            // out interceptors configured for that operation
+            let mut builder = runtime_components.to_builder();
+            builder.set_interceptors(std::iter::empty::<SharedInterceptor>());
+            config_builder.runtime_components = builder;
+
+            let client = crate::Client::from_conf(config_builder.build());
+            let response = client
+                .create_session()
+                .bucket(bucket_name)
+                .session_mode(crate::types::SessionMode::ReadWrite)
+                .send()
+                .await?;
+
+            response
+                .credentials
+                .ok_or("no session credentials in response".into())
+        }
     }
 
     impl Builder {
@@ -105,14 +234,13 @@ pub(crate) mod identity_provider {
         }
     }
 
-    impl ProvideCredentials for DefaultS3ExpressIdentityProvider {
-        fn provide_credentials<'a>(
+    impl ResolveIdentity for DefaultS3ExpressIdentityProvider {
+        fn resolve_identity<'a>(
             &'a self,
-        ) -> aws_credential_types::provider::future::ProvideCredentials<'a>
-        where
-            Self: 'a,
-        {
-            todo!()
+            runtime_components: &'a RuntimeComponents,
+            config_bag: &'a ConfigBag,
+        ) -> IdentityFuture<'a> {
+            IdentityFuture::new(async move { self.identity(runtime_components, config_bag).await })
         }
     }
 }
diff --git a/aws/rust-runtime/aws-runtime/src/auth/sigv4.rs b/aws/rust-runtime/aws-runtime/src/auth/sigv4.rs
index 1e3dc5ad39..c422a86a78 100644
--- a/aws/rust-runtime/aws-runtime/src/auth/sigv4.rs
+++ b/aws/rust-runtime/aws-runtime/src/auth/sigv4.rs
@@ -72,7 +72,8 @@ impl SigV4Signer {
         Self
     }
 
-    fn settings(operation_config: &SigV4OperationSigningConfig) -> SigningSettings {
+    /// Creates a [`SigningSettings`] from the given `operation_config`.
+    pub fn signing_settings(operation_config: &SigV4OperationSigningConfig) -> SigningSettings {
         super::settings(operation_config)
     }
 
@@ -117,10 +118,11 @@ impl SigV4Signer {
             .expect("all required fields set"))
     }
 
-    fn extract_operation_config<'a>(
+    /// Extracts a [`SigV4OperationSigningConfig`].
+    pub fn extract_operation_config<'a>(
         auth_scheme_endpoint_config: AuthSchemeEndpointConfig<'a>,
         config_bag: &'a ConfigBag,
-    ) -> Result<Cow<'a, SigV4OperationSigningConfig>, SigV4SigningError> {
+    ) -> Result<Cow<'a, SigV4OperationSigningConfig>, BoxError> {
         let operation_config = config_bag
             .load::<SigV4OperationSigningConfig>()
             .ok_or(SigV4SigningError::MissingOperationSigningConfig)?;
@@ -141,28 +143,23 @@ impl SigV4Signer {
             }
         }
     }
-}
 
-impl Sign for SigV4Signer {
-    fn sign_http_request(
+    /// Signs the given `request`.
+    ///
+    /// This is a helper used by [`Sign::sign_http_request`] and will be useful if calling code
+    /// needs to pass a configured `settings`.
+    pub fn sign_http_request(
         &self,
         request: &mut HttpRequest,
         identity: &Identity,
-        auth_scheme_endpoint_config: AuthSchemeEndpointConfig<'_>,
+        settings: SigningSettings,
+        operation_config: &SigV4OperationSigningConfig,
         runtime_components: &RuntimeComponents,
-        config_bag: &ConfigBag,
+        #[allow(unused_variables)] config_bag: &ConfigBag,
     ) -> Result<(), BoxError> {
-        let operation_config =
-            Self::extract_operation_config(auth_scheme_endpoint_config, config_bag)?;
         let request_time = runtime_components.time_source().unwrap_or_default().now();
-
-        if identity.data::<Credentials>().is_none() {
-            return Err(SigV4SigningError::WrongIdentityType(identity.clone()).into());
-        };
-
-        let settings = Self::settings(&operation_config);
         let signing_params =
-            Self::signing_params(settings, identity, &operation_config, request_time)?;
+            Self::signing_params(settings, identity, operation_config, request_time)?;
 
         let (signing_instructions, _signature) = {
             // A body that is already in memory can be signed directly. A body that is not in memory
@@ -218,6 +215,35 @@ impl Sign for SigV4Signer {
     }
 }
 
+impl Sign for SigV4Signer {
+    fn sign_http_request(
+        &self,
+        request: &mut HttpRequest,
+        identity: &Identity,
+        auth_scheme_endpoint_config: AuthSchemeEndpointConfig<'_>,
+        runtime_components: &RuntimeComponents,
+        config_bag: &ConfigBag,
+    ) -> Result<(), BoxError> {
+        if identity.data::<Credentials>().is_none() {
+            return Err(SigV4SigningError::WrongIdentityType(identity.clone()).into());
+        };
+
+        let operation_config =
+            Self::extract_operation_config(auth_scheme_endpoint_config, config_bag)?;
+
+        let settings = Self::signing_settings(&operation_config);
+
+        self.sign_http_request(
+            request,
+            identity,
+            settings,
+            &operation_config,
+            runtime_components,
+            config_bag,
+        )
+    }
+}
+
 #[cfg(feature = "event-stream")]
 mod event_stream {
     use aws_sigv4::event_stream::{sign_empty_message, sign_message};
diff --git a/aws/rust-runtime/aws-sigv4/src/http_request/sign.rs b/aws/rust-runtime/aws-sigv4/src/http_request/sign.rs
index 2f27b3c4b7..ff814703fe 100644
--- a/aws/rust-runtime/aws-sigv4/src/http_request/sign.rs
+++ b/aws/rust-runtime/aws-sigv4/src/http_request/sign.rs
@@ -366,12 +366,23 @@ fn calculate_signing_headers<'a>(
             }
 
             if let Some(security_token) = creds.session_token() {
-                add_header(
-                    &mut headers,
-                    header::X_AMZ_SECURITY_TOKEN,
-                    security_token,
-                    true,
-                );
+                if !params
+                    .settings
+                    .excluded_headers
+                    .as_ref()
+                    .is_some_and(|headers| {
+                        headers
+                            .iter()
+                            .any(|header| header == header::X_AMZ_SECURITY_TOKEN)
+                    })
+                {
+                    add_header(
+                        &mut headers,
+                        header::X_AMZ_SECURITY_TOKEN,
+                        security_token,
+                        true,
+                    );
+                }
             }
             signature
         }
diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3Decorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3Decorator.kt
index 5c91ead09a..42feb58048 100644
--- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3Decorator.kt
+++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3Decorator.kt
@@ -53,6 +53,7 @@ class S3Decorator : ClientCodegenDecorator {
     private val invalidXmlRootAllowList =
         setOf(
             // API returns GetObjectAttributes_Response_ instead of Output
+            ShapeId.from("com.amazonaws.s3#CreateSessionOutput"),
             ShapeId.from("com.amazonaws.s3#GetObjectAttributesOutput"),
         )
 
diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
index f12bec3e2d..b9e2790501 100644
--- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
+++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
@@ -85,11 +85,6 @@ private class S3ExpressServiceRuntimePluginCustomization(codegenContext: ClientC
             "SharedAuthScheme" to
                 RuntimeType.smithyRuntimeApiClient(runtimeConfig)
                     .resolve("client::auth::SharedAuthScheme"),
-            "SharedCredentialsProvider" to
-                configReexport(
-                    AwsRuntimeType.awsCredentialTypes(runtimeConfig)
-                        .resolve("provider::SharedCredentialsProvider"),
-                ),
             "SharedIdentityResolver" to
                 RuntimeType.smithyRuntimeApiClient(runtimeConfig)
                     .resolve("client::identity::SharedIdentityResolver"),
@@ -116,9 +111,7 @@ private class S3ExpressServiceRuntimePluginCustomization(codegenContext: ClientC
                             rustTemplate(
                                 """
                                 #{SharedIdentityResolver}::new_with_cache_location(
-                                        #{SharedCredentialsProvider}::new(
-                                            #{DefaultS3ExpressIdentityProvider}::builder().build()
-                                        ),
+                                        #{DefaultS3ExpressIdentityProvider}::builder().build(),
                                         #{IdentityCacheLocation}::IdentityResolver,
                                 )
                                 """,
diff --git a/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs b/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs
index dc9f65d56a..83b4b06a5a 100644
--- a/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs
+++ b/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs
@@ -377,12 +377,37 @@ declare_runtime_components! {
     }
 }
 
+impl From<RuntimeComponents> for RuntimeComponentsBuilder {
+    fn from(rc: RuntimeComponents) -> Self {
+        RuntimeComponentsBuilder {
+            builder_name: "converted from RuntimeComponents",
+            auth_scheme_option_resolver: Some(rc.auth_scheme_option_resolver),
+            http_client: rc.http_client,
+            endpoint_resolver: Some(rc.endpoint_resolver),
+            auth_schemes: rc.auth_schemes,
+            identity_cache: Some(rc.identity_cache),
+            identity_resolvers: Some(rc.identity_resolvers),
+            interceptors: rc.interceptors,
+            retry_classifiers: rc.retry_classifiers,
+            retry_strategy: Some(rc.retry_strategy),
+            time_source: rc.time_source,
+            sleep_impl: rc.sleep_impl,
+            config_validators: rc.config_validators,
+        }
+    }
+}
+
 impl RuntimeComponents {
     /// Returns a builder for runtime components.
     pub fn builder(name: &'static str) -> RuntimeComponentsBuilder {
         RuntimeComponentsBuilder::new(name)
     }
 
+    /// Clones and converts this [`RuntimeComponents`] into a [`RuntimeComponentsBuilder`].
+    pub fn to_builder(&self) -> RuntimeComponentsBuilder {
+        self.clone().into()
+    }
+
     /// Returns the auth scheme option resolver.
     pub fn auth_scheme_option_resolver(&self) -> SharedAuthSchemeOptionResolver {
         self.auth_scheme_option_resolver.value.clone()

From 67223e311970bfb7cb46b9333b702a8616bd3c81 Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Mon, 29 Jan 2024 16:30:28 -0600
Subject: [PATCH 09/29] Add recording test for S3 Express list-objects-v2

---
 .../tests/data/express/list-objects-v2.json   | 193 ++++++++++++++++++
 aws/sdk/integration-tests/s3/tests/express.rs |  39 ++++
 2 files changed, 232 insertions(+)
 create mode 100644 aws/sdk/integration-tests/s3/tests/data/express/list-objects-v2.json
 create mode 100644 aws/sdk/integration-tests/s3/tests/express.rs

diff --git a/aws/sdk/integration-tests/s3/tests/data/express/list-objects-v2.json b/aws/sdk/integration-tests/s3/tests/data/express/list-objects-v2.json
new file mode 100644
index 0000000000..6d04afe1c8
--- /dev/null
+++ b/aws/sdk/integration-tests/s3/tests/data/express/list-objects-v2.json
@@ -0,0 +1,193 @@
+{
+  "events": [
+    {
+      "connection_id": 0,
+      "action": {
+        "Request": {
+          "request": {
+            "uri": "https://s3express-test-bucket--usw2-az1--x-s3.s3express-usw2-az1.us-west-2.amazonaws.com/?session",
+            "headers": {
+              "amz-sdk-request": [
+                "attempt=1; max=1"
+              ],
+              "x-amz-user-agent": [
+                "aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0"
+              ],
+              "x-amz-create-session-mode": [
+                "ReadWrite"
+              ],
+              "x-amz-date": [
+                "20090213T233130Z"
+              ],
+              "authorization": [
+                "AWS4-HMAC-SHA256 Credential=ANOTREAL/20090213/us-west-2/s3express/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-create-session-mode;x-amz-date;x-amz-user-agent, Signature=4d44fb95628114b17a0676e2da758dee74f8a0337a3f0183e5b91e4fea6d9303"
+              ],
+              "user-agent": [
+                "aws-sdk-rust/0.123.test os/windows/XPSP3 lang/rust/1.50.0"
+              ]
+            },
+            "method": "GET"
+          }
+        }
+      }
+    },
+    {
+      "connection_id": 0,
+      "action": {
+        "Eof": {
+          "ok": true,
+          "direction": "Request"
+        }
+      }
+    },
+    {
+      "connection_id": 0,
+      "action": {
+        "Response": {
+          "response": {
+            "Ok": {
+              "status": 200,
+              "headers": {
+                "x-amz-id-2": [
+                  "TQk2NSay"
+                ],
+                "x-amz-request-id": [
+                  "0033eada6b00018d568cbe9f0509499a7de17df8"
+                ],
+                "date": [
+                  "Mon, 29 Jan 2024 18:48:00 GMT"
+                ],
+                "content-type": [
+                  "application/xml"
+                ],
+                "content-length": [
+                  "1035"
+                ],
+                "server": [
+                  "AmazonS3"
+                ]
+              }
+            }
+          }
+        }
+      }
+    },
+    {
+      "connection_id": 0,
+      "action": {
+        "Data": {
+          "data": {
+            "Utf8": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CreateSessionResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><Credentials><SessionToken>AgAAAGxnCC7+1qgZF9Zo1aMcI+JZNlNSXzzvpCif4IsEAAAAAAAAADAoC5fHAQAAAAAAAK5b/HX2sWg7Eb+jLXyaCWq0KEMdETvdCBl/bqHtnVkbjoT2p4K7FXiJy7J6VBuCvQhcIlnINa6ed7GF2xgzFNyENQkps2RpLj1lEqWmPAtnoeQqWqYSPwnKh+TVL4vGXfV9mFEeZMEW8eP7o/BWRtYg2ERp3+vUGwRhFRXXIjwTrKe76U/l7mSK79xRV6nMxKJi4/tNG98GKX7FGdEU/dVKEhpe1mRvltkVyA9KnkIwvysLsQLN+rUsbmPhvMManqGCSWqpjbbETp2RUVbg3Vxa9bvlzfW8+BR0CdrZ1QUi5NdwV6gAaJZ8TzNfdvwZJy4asC6ay3t6VBVFtcV+yfWdNx5pHOnxm7siiIbW8iv0jZzuJCzk36QoOAP8Tt3bVOJ592sgkt/ZF1LcmPC1BCXzwG7uuexPdOuoG3WbkEKQxv7Qa84JooPQjaWSHVgQONdLMSSCXjuPn9YAeTyeuOkpARBHlf+KT0D72ISLvZFHn/j/gxnZww2hJUoKpM5obWdbij4yNH+DW8FHmAnRf5DWTBSLWk6SFpE7UvUCRb3LqxAuu0SoaRmdJACtBcKAIgr2HiPwULHYbOlkcKcj5K5W1UA9ssvd</SessionToken><SecretAccessKey>HR6zWlAl1yjsuP8jo/Rw6aqaooVeDeOM2EMn35/b</SecretAccessKey><AccessKeyId>CT7ODKCW3E7XYBDHMKLEOIBWIA</AccessKeyId><Expiration>2024-01-29T18:53:01Z</Expiration></Credentials></CreateSessionResult>"
+          },
+          "direction": "Response"
+        }
+      }
+    },
+    {
+      "connection_id": 0,
+      "action": {
+        "Eof": {
+          "ok": true,
+          "direction": "Response"
+        }
+      }
+    },
+    {
+      "connection_id": 1,
+      "action": {
+        "Request": {
+          "request": {
+            "uri": "https://s3express-test-bucket--usw2-az1--x-s3.s3express-usw2-az1.us-west-2.amazonaws.com/?list-type=2",
+            "headers": {
+              "authorization": [
+                "AWS4-HMAC-SHA256 Credential=CT7ODKCW3E7XYBDHMKLEOIBWIA/20090213/us-west-2/s3express/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-s3session-token;x-amz-user-agent, Signature=12751fd6558c96b00f3dd624602b0f89e969a8885bada0f5e8b251953ef4e203"
+              ],
+              "x-amz-date": [
+                "20090213T233130Z"
+              ],
+              "amz-sdk-request": [
+                "attempt=1; max=3"
+              ],
+              "x-amz-user-agent": [
+                "aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0"
+              ],
+              "x-amz-s3session-token": [
+                "AgAAAGxnCC7+1qgZF9Zo1aMcI+JZNlNSXzzvpCif4IsEAAAAAAAAADAoC5fHAQAAAAAAAK5b/HX2sWg7Eb+jLXyaCWq0KEMdETvdCBl/bqHtnVkbjoT2p4K7FXiJy7J6VBuCvQhcIlnINa6ed7GF2xgzFNyENQkps2RpLj1lEqWmPAtnoeQqWqYSPwnKh+TVL4vGXfV9mFEeZMEW8eP7o/BWRtYg2ERp3+vUGwRhFRXXIjwTrKe76U/l7mSK79xRV6nMxKJi4/tNG98GKX7FGdEU/dVKEhpe1mRvltkVyA9KnkIwvysLsQLN+rUsbmPhvMManqGCSWqpjbbETp2RUVbg3Vxa9bvlzfW8+BR0CdrZ1QUi5NdwV6gAaJZ8TzNfdvwZJy4asC6ay3t6VBVFtcV+yfWdNx5pHOnxm7siiIbW8iv0jZzuJCzk36QoOAP8Tt3bVOJ592sgkt/ZF1LcmPC1BCXzwG7uuexPdOuoG3WbkEKQxv7Qa84JooPQjaWSHVgQONdLMSSCXjuPn9YAeTyeuOkpARBHlf+KT0D72ISLvZFHn/j/gxnZww2hJUoKpM5obWdbij4yNH+DW8FHmAnRf5DWTBSLWk6SFpE7UvUCRb3LqxAuu0SoaRmdJACtBcKAIgr2HiPwULHYbOlkcKcj5K5W1UA9ssvd"
+              ],
+              "user-agent": [
+                "aws-sdk-rust/0.123.test os/windows/XPSP3 lang/rust/1.50.0"
+              ]
+            },
+            "method": "GET"
+          }
+        }
+      }
+    },
+    {
+      "connection_id": 1,
+      "action": {
+        "Eof": {
+          "ok": true,
+          "direction": "Request"
+        }
+      }
+    },
+    {
+      "connection_id": 1,
+      "action": {
+        "Response": {
+          "response": {
+            "Ok": {
+              "status": 200,
+              "headers": {
+                "content-type": [
+                  "application/xml"
+                ],
+                "date": [
+                  "Mon, 29 Jan 2024 18:48:00 GMT"
+                ],
+                "x-amz-request-id": [
+                  "0033eada6b00018d568cbf350509f775295f94b5"
+                ],
+                "x-amz-id-2": [
+                  "IltTpRJVF1U"
+                ],
+                "server": [
+                  "AmazonS3"
+                ],
+                "content-length": [
+                  "520"
+                ],
+                "x-amz-bucket-region": [
+                  "us-west-2"
+                ]
+              }
+            }
+          }
+        }
+      }
+    },
+    {
+      "connection_id": 1,
+      "action": {
+        "Data": {
+          "data": {
+            "Utf8": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<ListBucketResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><Name>s3express-test-bucket--usw2-az1--x-s3</Name><Prefix/><KeyCount>1</KeyCount><MaxKeys>1000</MaxKeys><IsTruncated>false</IsTruncated><Contents><ChecksumAlgorithm>CRC32</ChecksumAlgorithm><ETag>&quot;b357dc928b454965a8dd11716a37dab8&quot;</ETag><Key>hello-world.txt</Key><LastModified>2024-01-29T18:32:24.000Z</LastModified><Size>14</Size><StorageClass>EXPRESS_ONEZONE</StorageClass></Contents></ListBucketResult>"
+          },
+          "direction": "Response"
+        }
+      }
+    },
+    {
+      "connection_id": 1,
+      "action": {
+        "Eof": {
+          "ok": true,
+          "direction": "Response"
+        }
+      }
+    }
+  ],
+  "docs": "traffic recording of executing list-objects-v2 against an S3 Express One Zone bucket",
+  "version": "V0"
+}
diff --git a/aws/sdk/integration-tests/s3/tests/express.rs b/aws/sdk/integration-tests/s3/tests/express.rs
new file mode 100644
index 0000000000..0fd36c48f2
--- /dev/null
+++ b/aws/sdk/integration-tests/s3/tests/express.rs
@@ -0,0 +1,39 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+use aws_sdk_s3::Config;
+use aws_smithy_runtime::client::http::test_util::dvr::ReplayingClient;
+use aws_smithy_runtime::test_util::capture_test_logs::capture_test_logs;
+
+#[tokio::test]
+async fn list_objects_v2() {
+    let _logs = capture_test_logs();
+
+    let http_client =
+        ReplayingClient::from_file("tests/data/express/list-objects-v2.json").unwrap();
+    let config = aws_config::from_env()
+        .http_client(http_client.clone())
+        .no_credentials()
+        .region("us-west-2")
+        .load()
+        .await;
+    let config = Config::from(&config)
+        .to_builder()
+        .with_test_defaults()
+        .build();
+    let client = aws_sdk_s3::Client::from_conf(config);
+
+    let result = client
+        .list_objects_v2()
+        .bucket("s3express-test-bucket--usw2-az1--x-s3")
+        .send()
+        .await;
+    dbg!(result).expect("success");
+
+    http_client
+        .validate_body_and_headers(Some(&["x-amz-s3session-token"]), "application/xml")
+        .await
+        .unwrap();
+}

From b30abb2e58859da5739a83476ee867d490a598ad Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Mon, 29 Jan 2024 20:31:12 -0600
Subject: [PATCH 10/29] Exclude `s3_express` from aws-inlineable's module tree

---
 aws/rust-runtime/aws-inlineable/src/lib.rs | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/aws/rust-runtime/aws-inlineable/src/lib.rs b/aws/rust-runtime/aws-inlineable/src/lib.rs
index 91811be46a..0ae9627703 100644
--- a/aws/rust-runtime/aws-inlineable/src/lib.rs
+++ b/aws/rust-runtime/aws-inlineable/src/lib.rs
@@ -31,10 +31,6 @@ pub mod presigning;
 /// Presigning interceptors
 pub mod presigning_interceptors;
 
-/// Supporting types for S3 Express.
-#[allow(dead_code)]
-pub mod s3_express;
-
 /// Special logic for extracting request IDs from S3's responses.
 #[allow(dead_code)]
 pub mod s3_request_id;

From 2fcd2f75a8b0f1c9c5274b4db418b6c086e46197 Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Mon, 29 Jan 2024 22:22:29 -0600
Subject: [PATCH 11/29] Enable S3 Express endpoint tests

---
 .../aws-inlineable/src/s3_express.rs          | 56 ++++++++++++++++++-
 .../endpoints/OperationInputTestGenerator.kt  |  8 ---
 2 files changed, 54 insertions(+), 10 deletions(-)

diff --git a/aws/rust-runtime/aws-inlineable/src/s3_express.rs b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
index 128573ca13..4d77d179c0 100644
--- a/aws/rust-runtime/aws-inlineable/src/s3_express.rs
+++ b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
@@ -204,8 +204,60 @@ pub(crate) mod identity_provider {
             runtime_components: &'a RuntimeComponents,
             config_bag: &'a ConfigBag,
         ) -> Result<SessionCredentials, BoxError> {
-            let mut config_builder = crate::Config::builder()
-                .region(config_bag.load::<aws_types::region::Region>().cloned());
+            let mut config_builder = crate::Config::builder();
+            config_builder.set_accelerate(
+                config_bag
+                    .load::<crate::config::Accelerate>()
+                    .map(|ty| ty.0),
+            );
+            config_builder.set_app_name(config_bag.load::<aws_types::app_name::AppName>().cloned());
+            config_builder.set_disable_multi_region_access_points(
+                config_bag
+                    .load::<crate::config::DisableMultiRegionAccessPoints>()
+                    .map(|ty| ty.0),
+            );
+            config_builder.set_endpoint_url(
+                config_bag
+                    .load::<::aws_types::endpoint_config::EndpointUrl>()
+                    .map(|ty| ty.0.clone()),
+            );
+            config_builder.set_force_path_style(
+                config_bag
+                    .load::<crate::config::ForcePathStyle>()
+                    .map(|ty| ty.0),
+            );
+            config_builder.set_region(config_bag.load::<::aws_types::region::Region>().cloned());
+            config_builder.set_retry_config(
+                config_bag
+                    .load::<aws_smithy_types::retry::RetryConfig>()
+                    .cloned(),
+            );
+            config_builder.set_retry_partition(
+                config_bag
+                    .load::<::aws_smithy_runtime::client::retries::RetryPartition>()
+                    .cloned(),
+            );
+            config_builder.set_timeout_config(
+                config_bag
+                    .load::<::aws_smithy_types::timeout::TimeoutConfig>()
+                    .cloned(),
+            );
+            config_builder.set_use_arn_region(
+                config_bag
+                    .load::<crate::config::UseArnRegion>()
+                    .map(|ty| ty.0),
+            );
+            config_builder.set_use_dual_stack(
+                config_bag
+                    .load::<::aws_types::endpoint_config::UseDualStack>()
+                    .map(|ty| ty.0),
+            );
+            config_builder.set_use_fips(
+                config_bag
+                    .load::<::aws_types::endpoint_config::UseFips>()
+                    .map(|ty| ty.0),
+            );
+
             // inherits all runtime components from a current S3 operation but clears out
             // out interceptors configured for that operation
             let mut builder = runtime_components.to_builder();
diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/OperationInputTestGenerator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/OperationInputTestGenerator.kt
index 544d30ea8f..5bcc870ae5 100644
--- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/OperationInputTestGenerator.kt
+++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/OperationInputTestGenerator.kt
@@ -126,17 +126,9 @@ class OperationInputTestGenerator(_ctx: ClientCodegenContext, private val test:
     private val model = ctx.model
     private val instantiator = ClientInstantiator(ctx)
 
-    /** tests using S3 Express bucket names need to be disabled until the implementation is in place **/
-    private fun EndpointTestCase.isSigV4S3Express() =
-        expect.endpoint.orNull()?.properties?.get("authSchemes")?.asArrayNode()?.orNull()
-            ?.map { it.expectObjectNode().expectStringMember("name").value }?.contains("sigv4-s3express") == true
-
     fun generateInput(testOperationInput: EndpointTestOperationInput) =
         writable {
             val operationName = testOperationInput.operationName.toSnakeCase()
-            if (test.isSigV4S3Express()) {
-                Attribute.shouldPanic("not yet implemented").render(this)
-            }
             tokioTest(safeName("operation_input_test_$operationName")) {
                 rustTemplate(
                     """

From 21ad106f3879cdf602d1c131e161efceb703252a Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Wed, 7 Feb 2024 10:11:23 -0600
Subject: [PATCH 12/29] Update
 aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt

Co-authored-by: John DiSanti <jdisanti@amazon.com>
---
 .../amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
index f12bec3e2d..6a0ca9d770 100644
--- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
+++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
@@ -177,7 +177,7 @@ class S3ExpressIdentityProviderConfig(codegenContext: ClientCodegenContext) : Co
 
                     rustBlockTemplate(
                         """
-                        /// Sets the credentials provider for S3 Express
+                        /// Sets the credentials provider for S3 Express One Zone
                         pub fn set_express_credentials_provider(&mut self, credentials_provider: #{Option}<#{SharedCredentialsProvider}>) -> &mut Self
                         """,
                         *codegenScope,

From 9acaf2938f8b5fce2863f8010be7be0a51acbba2 Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Thu, 8 Feb 2024 10:48:16 -0600
Subject: [PATCH 13/29] Support presigning for S3 Express

---
 .../aws-inlineable/src/s3_express.rs          | 95 ++++++++++++++++---
 .../src/http_request/canonical_request.rs     | 14 ++-
 .../aws-sigv4/src/http_request/settings.rs    | 20 ++++
 .../aws-sigv4/src/http_request/sign.rs        | 21 ++--
 4 files changed, 120 insertions(+), 30 deletions(-)

diff --git a/aws/rust-runtime/aws-inlineable/src/s3_express.rs b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
index 4d77d179c0..3589073d9e 100644
--- a/aws/rust-runtime/aws-inlineable/src/s3_express.rs
+++ b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
@@ -6,9 +6,11 @@
 /// Supporting code for S3 Express auth
 pub(crate) mod auth {
     use std::borrow::Cow;
+    use std::str::FromStr;
 
     use aws_credential_types::Credentials;
     use aws_runtime::auth::sigv4::SigV4Signer;
+    use aws_sigv4::http_request::{SignatureLocation, SigningSettings};
     use aws_smithy_runtime_api::box_error::BoxError;
     use aws_smithy_runtime_api::client::auth::{
         AuthScheme, AuthSchemeEndpointConfig, AuthSchemeId, Sign,
@@ -68,26 +70,13 @@ pub(crate) mod auth {
         ) -> Result<(), BoxError> {
             let operation_config =
                 SigV4Signer::extract_operation_config(auth_scheme_endpoint_config, config_bag)?;
-
             let mut settings = SigV4Signer::signing_settings(&operation_config);
-            if let Some(excluded) = settings.excluded_headers.as_mut() {
-                excluded.push(Cow::Borrowed("x-amz-security-token"));
-            }
 
             let express_credentials = identity.data::<Credentials>().ok_or(
                 "wrong identity type for SigV4. Expected AWS credentials but got `{identity:?}",
             )?;
-            let mut value = http::HeaderValue::from_str(
-                express_credentials
-                    .session_token()
-                    .expect("S3 session token should be set"),
-            )
-            .unwrap();
-            value.set_sensitive(true);
-            request.headers_mut().insert(
-                http::HeaderName::from_static("x-amz-s3session-token"),
-                value,
-            );
+
+            add_token_to_request(express_credentials, request, &mut settings);
 
             SigV4Signer.sign_http_request(
                 request,
@@ -99,6 +88,82 @@ pub(crate) mod auth {
             )
         }
     }
+
+    fn add_token_to_request(
+        express_credentials: &Credentials,
+        request: &mut HttpRequest,
+        settings: &mut SigningSettings,
+    ) {
+        match settings.signature_location {
+            SignatureLocation::Headers => {
+                let security_token_header = Cow::Borrowed("x-amz-security-token");
+                match settings.excluded_headers.as_mut() {
+                    Some(excluded) => {
+                        excluded.push(security_token_header);
+                    }
+                    None => {
+                        settings
+                            .excluded_params
+                            .get_or_insert(vec![security_token_header]);
+                    }
+                }
+                let mut value = http::HeaderValue::from_str(
+                    express_credentials
+                        .session_token()
+                        .expect("S3 session token should be set"),
+                )
+                .unwrap();
+                value.set_sensitive(true);
+                request.headers_mut().insert(
+                    http::HeaderName::from_static("x-amz-s3session-token"),
+                    value,
+                );
+            }
+            SignatureLocation::QueryParams => {
+                let security_token_param = Cow::Borrowed("X-Amz-Security-Token");
+                match settings.excluded_params.as_mut() {
+                    Some(excluded) => {
+                        excluded.push(security_token_param);
+                    }
+                    None => {
+                        settings
+                            .excluded_params
+                            .get_or_insert(vec![security_token_param]);
+                    }
+                }
+                let uri = http::Uri::from_str(request.uri()).unwrap();
+                let mut query_params = match uri.query() {
+                    Some(query) => query.split('&').collect(),
+                    None => vec![],
+                };
+                let param = &format!(
+                    "X-Amz-S3session-Token={}",
+                    aws_smithy_http::query::fmt_string(
+                        express_credentials
+                            .session_token()
+                            .expect("S3 session token should be set")
+                    )
+                );
+                query_params.push(param);
+                let uri = http::Uri::builder()
+                    .authority(
+                        uri.authority()
+                            .expect("request URI should have authority set")
+                            .clone(),
+                    )
+                    .scheme(
+                        uri.scheme()
+                            .expect("request URI should have scheme set")
+                            .clone(),
+                    )
+                    .path_and_query(format!("{}?{}", uri.path(), query_params.join("&")))
+                    .build()
+                    .expect("unable to construct new URI");
+                request.set_uri(uri).unwrap();
+            }
+            _ => todo!(),
+        }
+    }
 }
 
 /// Supporting code for S3 Express identity cache
diff --git a/aws/rust-runtime/aws-sigv4/src/http_request/canonical_request.rs b/aws/rust-runtime/aws-sigv4/src/http_request/canonical_request.rs
index 5fae247dd2..43e31c0ac1 100644
--- a/aws/rust-runtime/aws-sigv4/src/http_request/canonical_request.rs
+++ b/aws/rust-runtime/aws-sigv4/src/http_request/canonical_request.rs
@@ -10,8 +10,8 @@ use crate::http_request::settings::UriPathNormalizationMode;
 use crate::http_request::sign::SignableRequest;
 use crate::http_request::uri_path_normalization::normalize_uri_path;
 use crate::http_request::url_escape::percent_encode_path;
-use crate::http_request::PercentEncodingMode;
 use crate::http_request::{PayloadChecksumKind, SignableBody, SignatureLocation, SigningParams};
+use crate::http_request::{PercentEncodingMode, SigningSettings};
 use crate::sign::v4::sha256_hex_string;
 use crate::SignatureVersion;
 use aws_smithy_http::query_writer::QueryWriter;
@@ -218,7 +218,7 @@ impl<'a> CanonicalRequest<'a> {
         let creq = CanonicalRequest {
             method: req.method(),
             path,
-            params: Self::params(req.uri(), &values),
+            params: Self::params(req.uri(), &values, params.settings()),
             headers: canonical_headers,
             values,
         };
@@ -320,7 +320,11 @@ impl<'a> CanonicalRequest<'a> {
         }
     }
 
-    fn params(uri: &Uri, values: &SignatureValues<'_>) -> Option<String> {
+    fn params(
+        uri: &Uri,
+        values: &SignatureValues<'_>,
+        settings: &SigningSettings,
+    ) -> Option<String> {
         let mut params: Vec<(Cow<'_, str>, Cow<'_, str>)> =
             form_urlencoded::parse(uri.query().unwrap_or_default().as_bytes()).collect();
         fn add_param<'a>(params: &mut Vec<(Cow<'a, str>, Cow<'a, str>)>, k: &'a str, v: &'a str) {
@@ -345,7 +349,9 @@ impl<'a> CanonicalRequest<'a> {
             );
 
             if let Some(security_token) = values.security_token {
-                add_param(&mut params, param::X_AMZ_SECURITY_TOKEN, security_token);
+                if !settings.param_excluded(param::X_AMZ_SECURITY_TOKEN) {
+                    add_param(&mut params, param::X_AMZ_SECURITY_TOKEN, security_token);
+                }
             }
         }
         // Sort by param name, and then by param value
diff --git a/aws/rust-runtime/aws-sigv4/src/http_request/settings.rs b/aws/rust-runtime/aws-sigv4/src/http_request/settings.rs
index 787619fc36..b79f9909ac 100644
--- a/aws/rust-runtime/aws-sigv4/src/http_request/settings.rs
+++ b/aws/rust-runtime/aws-sigv4/src/http_request/settings.rs
@@ -30,6 +30,9 @@ pub struct SigningSettings {
     /// Headers that should be excluded from the signing process
     pub excluded_headers: Option<Vec<Cow<'static, str>>>,
 
+    /// Query params that should be excluded from the signing process
+    pub excluded_params: Option<Vec<Cow<'static, str>>>,
+
     /// Specifies whether the absolute path component of the URI should be normalized during signing.
     pub uri_path_normalization_mode: UriPathNormalizationMode,
 
@@ -39,6 +42,22 @@ pub struct SigningSettings {
     pub session_token_mode: SessionTokenMode,
 }
 
+impl SigningSettings {
+    pub(crate) fn header_excluded(&self, header: impl Into<Cow<'static, str>>) -> bool {
+        let header = header.into();
+        self.excluded_headers
+            .as_ref()
+            .is_some_and(|headers| headers.iter().any(|h| h == &header))
+    }
+
+    pub(crate) fn param_excluded(&self, param: impl Into<Cow<'static, str>>) -> bool {
+        let param = param.into();
+        self.excluded_params
+            .as_ref()
+            .is_some_and(|params| params.iter().any(|p| p == &param))
+    }
+}
+
 /// HTTP payload checksum type
 #[non_exhaustive]
 #[derive(Debug, Eq, PartialEq)]
@@ -131,6 +150,7 @@ impl Default for SigningSettings {
             signature_location: SignatureLocation::Headers,
             expires_in: None,
             excluded_headers,
+            excluded_params: None,
             uri_path_normalization_mode: UriPathNormalizationMode::Enabled,
             session_token_mode: SessionTokenMode::Include,
         }
diff --git a/aws/rust-runtime/aws-sigv4/src/http_request/sign.rs b/aws/rust-runtime/aws-sigv4/src/http_request/sign.rs
index ff814703fe..f7b6a4b664 100644
--- a/aws/rust-runtime/aws-sigv4/src/http_request/sign.rs
+++ b/aws/rust-runtime/aws-sigv4/src/http_request/sign.rs
@@ -296,10 +296,15 @@ fn calculate_signing_params<'a>(
     }
 
     if let Some(security_token) = creds.session_token() {
-        signing_params.push((
-            param::X_AMZ_SECURITY_TOKEN,
-            Cow::Owned(security_token.to_string()),
-        ));
+        if !params
+            .settings()
+            .param_excluded(param::X_AMZ_SECURITY_TOKEN)
+        {
+            signing_params.push((
+                param::X_AMZ_SECURITY_TOKEN,
+                Cow::Owned(security_token.to_string()),
+            ));
+        }
     }
 
     Ok((signing_params, signature))
@@ -368,13 +373,7 @@ fn calculate_signing_headers<'a>(
             if let Some(security_token) = creds.session_token() {
                 if !params
                     .settings
-                    .excluded_headers
-                    .as_ref()
-                    .is_some_and(|headers| {
-                        headers
-                            .iter()
-                            .any(|header| header == header::X_AMZ_SECURITY_TOKEN)
-                    })
+                    .header_excluded(header::X_AMZ_SECURITY_TOKEN)
                 {
                     add_header(
                         &mut headers,

From ec08ae9c9c3ff7a522eacd1881a2034652dca0fe Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Thu, 8 Feb 2024 10:50:15 -0600
Subject: [PATCH 14/29] Add integration test for S3 Express `get_object`
 presigning

---
 aws/sdk/integration-tests/s3/tests/express.rs | 94 ++++++++++++++++++-
 1 file changed, 93 insertions(+), 1 deletion(-)

diff --git a/aws/sdk/integration-tests/s3/tests/express.rs b/aws/sdk/integration-tests/s3/tests/express.rs
index 0fd36c48f2..cc0d99aa58 100644
--- a/aws/sdk/integration-tests/s3/tests/express.rs
+++ b/aws/sdk/integration-tests/s3/tests/express.rs
@@ -3,9 +3,16 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 
-use aws_sdk_s3::Config;
+use std::time::{Duration, SystemTime};
+
+use aws_config::Region;
+use aws_sdk_s3::presigning::PresigningConfig;
+use aws_sdk_s3::primitives::SdkBody;
+use aws_sdk_s3::{Client, Config};
 use aws_smithy_runtime::client::http::test_util::dvr::ReplayingClient;
+use aws_smithy_runtime::client::http::test_util::{ReplayEvent, StaticReplayClient};
 use aws_smithy_runtime::test_util::capture_test_logs::capture_test_logs;
+use http::Uri;
 
 #[tokio::test]
 async fn list_objects_v2() {
@@ -37,3 +44,88 @@ async fn list_objects_v2() {
         .await
         .unwrap();
 }
+
+fn create_session_request() -> http::Request<SdkBody> {
+    http::Request::builder()
+        .uri("https://s3express-test-bucket--usw2-az1--x-s3.s3express-usw2-az1.us-west-2.amazonaws.com/?session")
+        .header("x-amz-create-session-mode", "ReadWrite")
+        .method("GET")
+        .body(SdkBody::empty())
+        .unwrap()
+}
+
+fn create_session_response() -> http::Response<SdkBody> {
+    http::Response::builder()
+        .status(200)
+        .body(SdkBody::from(
+            r#"<?xml version="1.0" encoding="UTF-8"?>
+            <CreateSessionResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
+                <Credentials>
+                    <SessionToken>TESTSESSIONTOKEN</SessionToken>
+                    <SecretAccessKey>TESTSECRETKEY</SecretAccessKey>
+                    <AccessKeyId>ASIARTESTID</AccessKeyId>
+                    <Expiration>2024-01-29T18:53:01Z</Expiration>
+                </Credentials>
+            </CreateSessionResult>
+            "#,
+        ))
+        .unwrap()
+}
+
+#[tokio::test]
+async fn presigning() {
+    let http_client = StaticReplayClient::new(vec![ReplayEvent::new(
+        create_session_request(),
+        create_session_response(),
+    )]);
+
+    let config = aws_sdk_s3::Config::builder()
+        .http_client(http_client)
+        .region(Region::new("us-west-2"))
+        .with_test_defaults()
+        .build();
+    let client = Client::from_conf(config);
+
+    let presigning_config = PresigningConfig::builder()
+        .start_time(SystemTime::UNIX_EPOCH + Duration::from_secs(1234567891))
+        .expires_in(Duration::from_secs(30))
+        .build()
+        .unwrap();
+
+    let presigned = client
+        .get_object()
+        .bucket("s3express-test-bucket--usw2-az1--x-s3")
+        .key("ferris.png")
+        .presigned(presigning_config)
+        .await
+        .unwrap();
+
+    let uri = presigned.uri().parse::<Uri>().unwrap();
+
+    let pq = uri.path_and_query().unwrap();
+    let path = pq.path();
+    let query = pq.query().unwrap();
+    let mut query_params: Vec<&str> = query.split('&').collect();
+    query_params.sort();
+
+    pretty_assertions::assert_eq!(
+        "s3express-test-bucket--usw2-az1--x-s3.s3express-usw2-az1.us-west-2.amazonaws.com",
+        uri.authority().unwrap()
+    );
+    assert_eq!("GET", presigned.method());
+    assert_eq!("/ferris.png", path);
+    pretty_assertions::assert_eq!(
+        &[
+            "X-Amz-Algorithm=AWS4-HMAC-SHA256",
+            "X-Amz-Credential=ASIARTESTID%2F20090213%2Fus-west-2%2Fs3express%2Faws4_request",
+            "X-Amz-Date=20090213T233131Z",
+            "X-Amz-Expires=30",
+            "X-Amz-S3session-Token=TESTSESSIONTOKEN",
+            "X-Amz-Signature=c09c93c7878184492cb960d59e148af932dff6b19609e63e3484599903d97e44",
+            "X-Amz-SignedHeaders=host",
+            "x-id=GetObject"
+        ][..],
+        &query_params
+    );
+    assert_eq!(presigned.headers().count(), 0);
+}

From c2a27086bc78319a07a9308ceb4549194a6263b4 Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Thu, 8 Feb 2024 15:52:36 -0600
Subject: [PATCH 15/29] Make `cache_location` a method on `ResolveIdentity`

This commit addresses https://github.com/smithy-lang/smithy-rs/pull/3386#discussion_r1480703708
---
 .../aws-inlineable/src/s3_express.rs          | 21 +++++++++-----
 .../customize/s3/S3ExpressDecorator.kt        | 19 ++-----------
 .../src/client/identity.rs                    | 28 ++++++++-----------
 .../src/client/orchestrator/auth.rs           |  1 +
 4 files changed, 29 insertions(+), 40 deletions(-)

diff --git a/aws/rust-runtime/aws-inlineable/src/s3_express.rs b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
index e7a9dfd08b..76b8a95093 100644
--- a/aws/rust-runtime/aws-inlineable/src/s3_express.rs
+++ b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
@@ -81,7 +81,11 @@ pub(crate) mod identity_cache {
 /// Supporting code for S3 Express identity provider
 pub(crate) mod identity_provider {
     use crate::s3_express::identity_cache::S3ExpressIdentityCache;
-    use aws_credential_types::provider::ProvideCredentials;
+    use aws_smithy_runtime_api::client::identity::{
+        IdentityCacheLocation, IdentityFuture, ResolveIdentity,
+    };
+    use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;
+    use aws_smithy_types::config_bag::ConfigBag;
 
     #[derive(Debug)]
     pub(crate) struct DefaultS3ExpressIdentityProvider {
@@ -105,14 +109,17 @@ pub(crate) mod identity_provider {
         }
     }
 
-    impl ProvideCredentials for DefaultS3ExpressIdentityProvider {
-        fn provide_credentials<'a>(
+    impl ResolveIdentity for DefaultS3ExpressIdentityProvider {
+        fn resolve_identity<'a>(
             &'a self,
-        ) -> aws_credential_types::provider::future::ProvideCredentials<'a>
-        where
-            Self: 'a,
-        {
+            _runtime_components: &'a RuntimeComponents,
+            _config_bag: &'a ConfigBag,
+        ) -> IdentityFuture<'a> {
             todo!()
         }
+
+        fn cache_location(&self) -> IdentityCacheLocation {
+            IdentityCacheLocation::IdentityResolver
+        }
     }
 }
diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
index 6a0ca9d770..cc5550615d 100644
--- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
+++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
@@ -113,17 +113,7 @@ private class S3ExpressServiceRuntimePluginCustomization(codegenContext: ClientC
                             rustTemplate("#{S3_EXPRESS_SCHEME_ID}", *codegenScope)
                         },
                         writable {
-                            rustTemplate(
-                                """
-                                #{SharedIdentityResolver}::new_with_cache_location(
-                                        #{SharedCredentialsProvider}::new(
-                                            #{DefaultS3ExpressIdentityProvider}::builder().build()
-                                        ),
-                                        #{IdentityCacheLocation}::IdentityResolver,
-                                )
-                                """,
-                                *codegenScope,
-                            )
+                            rustTemplate("#{DefaultS3ExpressIdentityProvider}::builder().build()", *codegenScope)
                         },
                     )
                 }
@@ -190,12 +180,7 @@ class S3ExpressIdentityProviderConfig(codegenContext: ClientCodegenContext) : Co
                         ) {
                             rustTemplate(
                                 """
-                                self.runtime_components.set_identity_resolver(
-                                    #{S3_EXPRESS_SCHEME_ID},
-                                    #{SharedIdentityResolver}::new_with_cache_location(
-                                        credentials_provider,
-                                        #{IdentityCacheLocation}::IdentityResolver),
-                                );
+                                self.runtime_components.set_identity_resolver(#{S3_EXPRESS_SCHEME_ID}, credentials_provider);
                                 """,
                                 *codegenScope,
                             )
diff --git a/rust-runtime/aws-smithy-runtime-api/src/client/identity.rs b/rust-runtime/aws-smithy-runtime-api/src/client/identity.rs
index acfd960020..c6a0a30c56 100644
--- a/rust-runtime/aws-smithy-runtime-api/src/client/identity.rs
+++ b/rust-runtime/aws-smithy-runtime-api/src/client/identity.rs
@@ -159,6 +159,14 @@ pub trait ResolveIdentity: Send + Sync + Debug {
     fn fallback_on_interrupt(&self) -> Option<Identity> {
         None
     }
+
+    /// Returns the location of an identity cache associated with this identity resolver.
+    ///
+    /// By default, identity resolvers will use the identity cache stored in runtime components.
+    /// Implementing types can change the cache location if they want to.
+    fn cache_location(&self) -> IdentityCacheLocation {
+        IdentityCacheLocation::RuntimeComponents
+    }
 }
 
 /// Cache location for identity caching.
@@ -181,25 +189,14 @@ pub enum IdentityCacheLocation {
 pub struct SharedIdentityResolver {
     inner: Arc<dyn ResolveIdentity>,
     cache_partition: IdentityCachePartition,
-    cache_location: IdentityCacheLocation,
 }
 
 impl SharedIdentityResolver {
     /// Creates a new [`SharedIdentityResolver`] from the given resolver.
     pub fn new(resolver: impl ResolveIdentity + 'static) -> Self {
-        Self::new_with_cache_location(resolver, IdentityCacheLocation::RuntimeComponents)
-    }
-
-    /// Creates a new [`SharedIdentityResolver`] from the given resolver with the additional argument
-    /// specifying where the identity cache location is.
-    pub fn new_with_cache_location(
-        resolver: impl ResolveIdentity + 'static,
-        cache_location: IdentityCacheLocation,
-    ) -> Self {
         Self {
             inner: Arc::new(resolver),
             cache_partition: IdentityCachePartition::new(),
-            cache_location,
         }
     }
 
@@ -210,11 +207,6 @@ impl SharedIdentityResolver {
     pub fn cache_partition(&self) -> IdentityCachePartition {
         self.cache_partition
     }
-
-    /// Returns where identities retrieved by this resolver are cached.
-    pub fn cache_location(&self) -> IdentityCacheLocation {
-        self.cache_location
-    }
 }
 
 impl ResolveIdentity for SharedIdentityResolver {
@@ -225,6 +217,10 @@ impl ResolveIdentity for SharedIdentityResolver {
     ) -> IdentityFuture<'a> {
         self.inner.resolve_identity(runtime_components, config_bag)
     }
+
+    fn cache_location(&self) -> IdentityCacheLocation {
+        self.inner.cache_location()
+    }
 }
 
 impl_shared_conversions!(convert SharedIdentityResolver from ResolveIdentity using SharedIdentityResolver::new);
diff --git a/rust-runtime/aws-smithy-runtime/src/client/orchestrator/auth.rs b/rust-runtime/aws-smithy-runtime/src/client/orchestrator/auth.rs
index ccca10bf34..0bf5ecf1a7 100644
--- a/rust-runtime/aws-smithy-runtime/src/client/orchestrator/auth.rs
+++ b/rust-runtime/aws-smithy-runtime/src/client/orchestrator/auth.rs
@@ -10,6 +10,7 @@ use aws_smithy_runtime_api::client::auth::{
     AuthScheme, AuthSchemeEndpointConfig, AuthSchemeId, AuthSchemeOptionResolverParams,
     ResolveAuthSchemeOptions,
 };
+use aws_smithy_runtime_api::client::identity::ResolveIdentity;
 use aws_smithy_runtime_api::client::identity::{IdentityCacheLocation, ResolveCachedIdentity};
 use aws_smithy_runtime_api::client::interceptors::context::InterceptorContext;
 use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;

From c4df9c72182585d644e4b5a5b27b110a69765745 Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Thu, 8 Feb 2024 17:13:52 -0600
Subject: [PATCH 16/29] Error instead of panic on missing bucket name

This commit addresses https://github.com/smithy-lang/smithy-rs/pull/3388#discussion_r1480717086
---
 aws/rust-runtime/aws-inlineable/src/s3_express.rs | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/aws/rust-runtime/aws-inlineable/src/s3_express.rs b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
index 3589073d9e..616fa6e926 100644
--- a/aws/rust-runtime/aws-inlineable/src/s3_express.rs
+++ b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
@@ -232,7 +232,7 @@ pub(crate) mod identity_provider {
             runtime_components: &'a RuntimeComponents,
             config_bag: &'a ConfigBag,
         ) -> Result<Identity, BoxError> {
-            let bucket_name = self.bucket_name(config_bag);
+            let bucket_name = self.bucket_name(config_bag)?;
 
             let sigv4_identity_resolver = runtime_components
                 .identity_resolver(aws_runtime::auth::sigv4::SCHEME_ID)
@@ -253,14 +253,16 @@ pub(crate) mod identity_provider {
             Ok(Identity::new(data.clone(), data.expiry()))
         }
 
-        fn bucket_name<'a>(&'a self, config_bag: &'a ConfigBag) -> &'a str {
+        fn bucket_name<'a>(&'a self, config_bag: &'a ConfigBag) -> Result<&'a str, BoxError> {
             let params = config_bag
                 .load::<EndpointResolverParams>()
                 .expect("endpoint resolver params must be set");
             let params = params
                 .get::<crate::config::endpoint::Params>()
                 .expect("`Params` should be wrapped in `EndpointResolverParams`");
-            params.bucket().expect("bucket name must be set")
+            params
+                .bucket()
+                .ok_or("A bucket was not set in endpoint params".into())
         }
 
         async fn express_session_credentials<'a>(

From 0e405e1da45d05666c30fae7a2d3ccb0177b49aa Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Thu, 8 Feb 2024 21:21:59 -0600
Subject: [PATCH 17/29] Error instead of panic in `add_token_to_request`

---
 .../aws-inlineable/src/s3_express.rs          | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/aws/rust-runtime/aws-inlineable/src/s3_express.rs b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
index 616fa6e926..4e5e9e216e 100644
--- a/aws/rust-runtime/aws-inlineable/src/s3_express.rs
+++ b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
@@ -76,7 +76,7 @@ pub(crate) mod auth {
                 "wrong identity type for SigV4. Expected AWS credentials but got `{identity:?}",
             )?;
 
-            add_token_to_request(express_credentials, request, &mut settings);
+            add_token_to_request(express_credentials, request, &mut settings)?;
 
             SigV4Signer.sign_http_request(
                 request,
@@ -93,7 +93,7 @@ pub(crate) mod auth {
         express_credentials: &Credentials,
         request: &mut HttpRequest,
         settings: &mut SigningSettings,
-    ) {
+    ) -> Result<(), BoxError> {
         match settings.signature_location {
             SignatureLocation::Headers => {
                 let security_token_header = Cow::Borrowed("x-amz-security-token");
@@ -148,21 +148,22 @@ pub(crate) mod auth {
                 let uri = http::Uri::builder()
                     .authority(
                         uri.authority()
-                            .expect("request URI should have authority set")
+                            .ok_or("request URI should have authority set")?
                             .clone(),
                     )
                     .scheme(
                         uri.scheme()
-                            .expect("request URI should have scheme set")
+                            .ok_or("request URI should have scheme set")?
                             .clone(),
                     )
                     .path_and_query(format!("{}?{}", uri.path(), query_params.join("&")))
-                    .build()
-                    .expect("unable to construct new URI");
-                request.set_uri(uri).unwrap();
+                    .build()?;
+                request.set_uri(uri)?
             }
-            _ => todo!(),
-        }
+            _ => { return Err(BoxError::from("`SignatureLocation` adds a new variant, which needs to be handled in a separate match arm")) },
+        };
+
+        Ok(())
     }
 }
 

From e47157f94e26bac80e9ec2faa6ca5e49fe072899 Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Thu, 8 Feb 2024 21:24:35 -0600
Subject: [PATCH 18/29] Update comment for `invalidXmlRootAllowList`

This commit addresses https://github.com/smithy-lang/smithy-rs/pull/3388#discussion_r1480723683
---
 .../software/amazon/smithy/rustsdk/customize/s3/S3Decorator.kt | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3Decorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3Decorator.kt
index 42feb58048..928a80f50c 100644
--- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3Decorator.kt
+++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3Decorator.kt
@@ -52,8 +52,9 @@ class S3Decorator : ClientCodegenDecorator {
     private val logger: Logger = Logger.getLogger(javaClass.name)
     private val invalidXmlRootAllowList =
         setOf(
-            // API returns GetObjectAttributes_Response_ instead of Output
+            // To work around https://github.com/awslabs/aws-sdk-rust/issues/991
             ShapeId.from("com.amazonaws.s3#CreateSessionOutput"),
+            // API returns GetObjectAttributes_Response_ instead of Output
             ShapeId.from("com.amazonaws.s3#GetObjectAttributesOutput"),
         )
 

From 5a4e3b29fc01ec663814408baa5c77423ba6d691 Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Thu, 8 Feb 2024 22:17:25 -0600
Subject: [PATCH 19/29] Implement `from_runtime_components` instead of `From`
 trait

This commit addresses https://github.com/smithy-lang/smithy-rs/pull/3388#discussion_r1480727356
---
 .../src/client/runtime_components.rs          | 25 ++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs b/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs
index 83b4b06a5a..35ce6c82eb 100644
--- a/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs
+++ b/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs
@@ -405,7 +405,10 @@ impl RuntimeComponents {
 
     /// Clones and converts this [`RuntimeComponents`] into a [`RuntimeComponentsBuilder`].
     pub fn to_builder(&self) -> RuntimeComponentsBuilder {
-        self.clone().into()
+        RuntimeComponentsBuilder::from_runtime_components(
+            self.clone(),
+            "RuntimeComponentsBuilder::from_runtime_components",
+        )
     }
 
     /// Returns the auth scheme option resolver.
@@ -507,6 +510,26 @@ impl RuntimeComponents {
 }
 
 impl RuntimeComponentsBuilder {
+    /// Creates a new [`RuntimeComponentsBuilder`], inheriting all fields from the given
+    /// [`RuntimeComponents`].
+    pub fn from_runtime_components(rc: RuntimeComponents, builder_name: &'static str) -> Self {
+        Self {
+            builder_name,
+            auth_scheme_option_resolver: Some(rc.auth_scheme_option_resolver),
+            http_client: rc.http_client,
+            endpoint_resolver: Some(rc.endpoint_resolver),
+            auth_schemes: rc.auth_schemes,
+            identity_cache: Some(rc.identity_cache),
+            identity_resolvers: Some(rc.identity_resolvers),
+            interceptors: rc.interceptors,
+            retry_classifiers: rc.retry_classifiers,
+            retry_strategy: Some(rc.retry_strategy),
+            time_source: rc.time_source,
+            sleep_impl: rc.sleep_impl,
+            config_validators: rc.config_validators,
+        }
+    }
+
     /// Returns the auth scheme option resolver.
     pub fn auth_scheme_option_resolver(&self) -> Option<SharedAuthSchemeOptionResolver> {
         self.auth_scheme_option_resolver

From 51518f9125f471ab1535b1becf5c18bc1b71370a Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Fri, 9 Feb 2024 16:31:22 -0600
Subject: [PATCH 20/29] Allow `config::Builder` to be created from `ConfigBag`

This commit addresses https://github.com/smithy-lang/smithy-rs/pull/3388#discussion_r1480718618
---
 .../aws-inlineable/src/s3_express.rs          | 60 ++-----------------
 .../rustsdk/EndpointBuiltInsDecorator.kt      |  1 -
 .../amazon/smithy/rustsdk/RegionDecorator.kt  |  4 ++
 .../smithy/rustsdk/UserAgentDecorator.kt      |  5 ++
 .../ResiliencyConfigCustomization.kt          | 15 +++++
 .../ClientContextConfigCustomization.kt       |  2 +-
 .../config/ServiceConfigGenerator.kt          | 54 +++++++++++++----
 ...lledStreamProtectionConfigCustomization.kt |  8 +++
 .../config/ServiceConfigGeneratorTest.kt      | 48 +++++++++++++++
 9 files changed, 127 insertions(+), 70 deletions(-)

diff --git a/aws/rust-runtime/aws-inlineable/src/s3_express.rs b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
index 4e5e9e216e..2609af7347 100644
--- a/aws/rust-runtime/aws-inlineable/src/s3_express.rs
+++ b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
@@ -272,65 +272,13 @@ pub(crate) mod identity_provider {
             runtime_components: &'a RuntimeComponents,
             config_bag: &'a ConfigBag,
         ) -> Result<SessionCredentials, BoxError> {
-            let mut config_builder = crate::Config::builder();
-            config_builder.set_accelerate(
-                config_bag
-                    .load::<crate::config::Accelerate>()
-                    .map(|ty| ty.0),
-            );
-            config_builder.set_app_name(config_bag.load::<aws_types::app_name::AppName>().cloned());
-            config_builder.set_disable_multi_region_access_points(
-                config_bag
-                    .load::<crate::config::DisableMultiRegionAccessPoints>()
-                    .map(|ty| ty.0),
-            );
-            config_builder.set_endpoint_url(
-                config_bag
-                    .load::<::aws_types::endpoint_config::EndpointUrl>()
-                    .map(|ty| ty.0.clone()),
-            );
-            config_builder.set_force_path_style(
-                config_bag
-                    .load::<crate::config::ForcePathStyle>()
-                    .map(|ty| ty.0),
-            );
-            config_builder.set_region(config_bag.load::<::aws_types::region::Region>().cloned());
-            config_builder.set_retry_config(
-                config_bag
-                    .load::<aws_smithy_types::retry::RetryConfig>()
-                    .cloned(),
-            );
-            config_builder.set_retry_partition(
-                config_bag
-                    .load::<::aws_smithy_runtime::client::retries::RetryPartition>()
-                    .cloned(),
-            );
-            config_builder.set_timeout_config(
-                config_bag
-                    .load::<::aws_smithy_types::timeout::TimeoutConfig>()
-                    .cloned(),
-            );
-            config_builder.set_use_arn_region(
-                config_bag
-                    .load::<crate::config::UseArnRegion>()
-                    .map(|ty| ty.0),
-            );
-            config_builder.set_use_dual_stack(
-                config_bag
-                    .load::<::aws_types::endpoint_config::UseDualStack>()
-                    .map(|ty| ty.0),
-            );
-            config_builder.set_use_fips(
-                config_bag
-                    .load::<::aws_types::endpoint_config::UseFips>()
-                    .map(|ty| ty.0),
-            );
+            let mut config_builder = crate::config::Builder::from_config_bag(config_bag);
 
             // inherits all runtime components from a current S3 operation but clears out
             // out interceptors configured for that operation
-            let mut builder = runtime_components.to_builder();
-            builder.set_interceptors(std::iter::empty::<SharedInterceptor>());
-            config_builder.runtime_components = builder;
+            let mut rc_builder = runtime_components.to_builder();
+            rc_builder.set_interceptors(std::iter::empty::<SharedInterceptor>());
+            config_builder.runtime_components = rc_builder;
 
             let client = crate::Client::from_conf(config_builder.build());
             let response = client
diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointBuiltInsDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointBuiltInsDecorator.kt
index 3a9b581549..7900b1ca56 100644
--- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointBuiltInsDecorator.kt
+++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/EndpointBuiltInsDecorator.kt
@@ -148,7 +148,6 @@ fun decoratorForBuiltIn(
                 standardConfigParam(
                     clientParamBuilder?.toConfigParam(builtIn, codegenContext.runtimeConfig) ?: ConfigParam.Builder()
                         .toConfigParam(builtIn, codegenContext.runtimeConfig),
-                    codegenContext,
                 )
             }
         }
diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionDecorator.kt
index c877d4aac5..37b9a59b40 100644
--- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionDecorator.kt
+++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/RegionDecorator.kt
@@ -211,6 +211,10 @@ class RegionProviderConfig(codegenContext: ClientCodegenContext) : ConfigCustomi
                     )
                 }
 
+                is ServiceConfig.BuilderFromConfigBag -> {
+                    rustTemplate("${section.builder}.set_region(${section.config_bag}.load::<#{Region}>().cloned());", *codegenScope)
+                }
+
                 else -> emptySection
             }
         }
diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/UserAgentDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/UserAgentDecorator.kt
index 927a4c8dd2..4325aee01b 100644
--- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/UserAgentDecorator.kt
+++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/UserAgentDecorator.kt
@@ -145,6 +145,11 @@ class UserAgentDecorator : ClientCodegenDecorator {
                         )
                     }
 
+                is ServiceConfig.BuilderFromConfigBag ->
+                    writable {
+                        rustTemplate("${section.builder}.set_app_name(${section.config_bag}.load::<#{AppName}>().cloned());", *codegenScope)
+                    }
+
                 is ServiceConfig.BuilderBuild ->
                     writable {
                         rust("layer.store_put(#T.clone());", ClientRustModule.Meta.toType().resolve("API_METADATA"))
diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/ResiliencyConfigCustomization.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/ResiliencyConfigCustomization.kt
index 8b6153b9a6..a0a6202358 100644
--- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/ResiliencyConfigCustomization.kt
+++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/ResiliencyConfigCustomization.kt
@@ -274,6 +274,21 @@ class ResiliencyConfigCustomization(codegenContext: ClientCodegenContext) : Conf
                     )
                 }
 
+                is ServiceConfig.BuilderFromConfigBag -> {
+                    rustTemplate(
+                        "${section.builder}.set_retry_config(${section.config_bag}.load::<#{RetryConfig}>().cloned());",
+                        *codegenScope,
+                    )
+                    rustTemplate(
+                        "${section.builder}.set_timeout_config(${section.config_bag}.load::<#{TimeoutConfig}>().cloned());",
+                        *codegenScope,
+                    )
+                    rustTemplate(
+                        "${section.builder}.set_retry_partition(${section.config_bag}.load::<#{RetryPartition}>().cloned());",
+                        *codegenScope,
+                    )
+                }
+
                 else -> emptySection
             }
         }
diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/ClientContextConfigCustomization.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/ClientContextConfigCustomization.kt
index 96ddb2083c..adf7bfddb5 100644
--- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/ClientContextConfigCustomization.kt
+++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/endpoint/ClientContextConfigCustomization.kt
@@ -40,7 +40,7 @@ class ClientContextConfigCustomization(ctx: ClientCodegenContext) : ConfigCustom
     private val configParams =
         ctx.serviceShape.getTrait<ClientContextParamsTrait>()?.parameters.orEmpty().toList()
             .map { (key, value) -> fromClientParam(key, value, ctx.symbolProvider, runtimeConfig) }
-    private val decorators = configParams.map { standardConfigParam(it, ctx) }
+    private val decorators = configParams.map { standardConfigParam(it) }
 
     companion object {
         fun toSymbol(
diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/ServiceConfigGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/ServiceConfigGenerator.kt
index 38fecb7e48..8bb9bcd039 100644
--- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/ServiceConfigGenerator.kt
+++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/ServiceConfigGenerator.kt
@@ -81,18 +81,22 @@ sealed class ServiceConfig(name: String) : Section(name) {
     object BuilderImpl : ServiceConfig("BuilderImpl")
 
     /**
-     * Convert from a field in the builder to the final field in config
+     * Load a value from a config bag and store it in ConfigBuilder
      *  e.g.
      *  ```kotlin
-     *  rust("""my_field: my_field.unwrap_or_else(||"default")""")
+     *  rust("""builder.set_field(config_bag.load::<FieldType>().cloned())""")
      *  ```
      */
-    object BuilderBuild : ServiceConfig("BuilderBuild")
+    data class BuilderFromConfigBag(val builder: String, val config_bag: String) : ServiceConfig("BuilderFromConfigBag")
 
     /**
-     * A section for customizing individual fields in the initializer of Config
+     * Convert from a field in the builder to the final field in config
+     *  e.g.
+     *  ```kotlin
+     *  rust("""my_field: my_field.unwrap_or_else(||"default")""")
+     *  ```
      */
-    object BuilderBuildExtras : ServiceConfig("BuilderBuildExtras")
+    object BuilderBuild : ServiceConfig("BuilderBuild")
 
     /**
      * A section for setting up a field to be used by ConfigOverrideRuntimePlugin
@@ -203,10 +207,7 @@ fun loadFromConfigBag(
  * 2. convenience setter (non-optional)
  * 3. standard setter (&mut self)
  */
-fun standardConfigParam(
-    param: ConfigParam,
-    codegenContext: ClientCodegenContext,
-): ConfigCustomization =
+fun standardConfigParam(param: ConfigParam): ConfigCustomization =
     object : ConfigCustomization() {
         override fun section(section: ServiceConfig): Writable {
             return when (section) {
@@ -235,6 +236,16 @@ fun standardConfigParam(
                         )
                     }
 
+                is ServiceConfig.BuilderFromConfigBag ->
+                    writable {
+                        rustTemplate(
+                            """
+                            ${section.builder}.set_${param.name}(${section.config_bag}.#{load_from_config_bag});
+                            """,
+                            "load_from_config_bag" to loadFromConfigBag(param.type.name, param.newtype!!),
+                        )
+                    }
+
                 else -> emptySection
             }
         }
@@ -305,6 +316,26 @@ class ServiceConfigGenerator(
                 ),
         )
 
+    private fun builderFromConfigBag() =
+        writable {
+            val builderVar = "builder"
+            val configBagVar = "config_bag"
+
+            docs("Constructs a config builder from the given `$configBagVar`, setting only fields stored in the config bag,")
+            docs("but not those in runtime components.")
+            Attribute.AllowUnused.render(this)
+            rustBlockTemplate(
+                "pub(crate) fn from_config_bag($configBagVar: &#{ConfigBag}) -> Self",
+                *codegenScope,
+            ) {
+                rust("let mut $builderVar = Self::new();")
+                customizations.forEach {
+                    it.section(ServiceConfig.BuilderFromConfigBag(builderVar, configBagVar))(this)
+                }
+                rust("$builderVar")
+            }
+        }
+
     private fun behaviorMv() =
         writable {
             val docs = """
@@ -451,6 +482,8 @@ class ServiceConfigGenerator(
         writer.rustBlock("impl Builder") {
             writer.docs("Constructs a config builder.")
             writer.rust("pub fn new() -> Self { Self::default() }")
+
+            builderFromConfigBag()(this)
             customizations.forEach {
                 it.section(ServiceConfig.BuilderImpl)(this)
             }
@@ -522,9 +555,6 @@ class ServiceConfigGenerator(
                     it.section(ServiceConfig.BuilderBuild)(this)
                 }
                 rustBlock("Config") {
-                    customizations.forEach {
-                        it.section(ServiceConfig.BuilderBuildExtras)(this)
-                    }
                     rustTemplate(
                         """
                         config: #{Layer}::from(layer.clone()).with_name("$moduleUseName::config::Config").freeze(),
diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/StalledStreamProtectionConfigCustomization.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/StalledStreamProtectionConfigCustomization.kt
index 0c67acbf43..83c3b6dd6b 100644
--- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/StalledStreamProtectionConfigCustomization.kt
+++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/StalledStreamProtectionConfigCustomization.kt
@@ -96,6 +96,14 @@ class StalledStreamProtectionConfigCustomization(codegenContext: ClientCodegenCo
                     )
                 }
 
+            is ServiceConfig.BuilderFromConfigBag ->
+                writable {
+                    rustTemplate(
+                        "${section.builder}.set_stalled_stream_protection(${section.config_bag}.load::<#{StalledStreamProtectionConfig}>().cloned());",
+                        *codegenScope,
+                    )
+                }
+
             else -> emptySection
         }
     }
diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/ServiceConfigGeneratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/ServiceConfigGeneratorTest.kt
index 4e9e88f414..e80d29efea 100644
--- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/ServiceConfigGeneratorTest.kt
+++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/ServiceConfigGeneratorTest.kt
@@ -15,6 +15,7 @@ import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest
 import software.amazon.smithy.rust.codegen.core.rustlang.Writable
 import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
 import software.amazon.smithy.rust.codegen.core.rustlang.writable
+import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig
 import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
 import software.amazon.smithy.rust.codegen.core.smithy.customize.NamedCustomization
 import software.amazon.smithy.rust.codegen.core.testutil.BasicTestModels
@@ -24,6 +25,11 @@ import software.amazon.smithy.rust.codegen.core.util.lookup
 import software.amazon.smithy.rust.codegen.core.util.toPascalCase
 
 internal class ServiceConfigGeneratorTest {
+    private fun codegenScope(rc: RuntimeConfig): Array<Pair<String, Any>> =
+        arrayOf(
+            "ConfigBag" to RuntimeType.configBag(rc),
+        )
+
     @Test
     fun `idempotency token when used`() {
         fun model(trait: String) =
@@ -124,6 +130,20 @@ internal class ServiceConfigGeneratorTest {
                             )
                         }
 
+                    is ServiceConfig.BuilderFromConfigBag ->
+                        writable {
+                            rustTemplate(
+                                """
+                                ${section.builder} = ${section.builder}.config_field(${section.config_bag}.load::<#{T}>().map(|u| u.0).unwrap());
+                                """,
+                                "T" to
+                                    configParamNewtype(
+                                        "config_field".toPascalCase(), RuntimeType.U64.toSymbol(),
+                                        codegenContext.runtimeConfig,
+                                    ),
+                            )
+                        }
+
                     else -> emptySection
                 }
             }
@@ -174,6 +194,34 @@ internal class ServiceConfigGeneratorTest {
                     assert_eq!(config.runtime_plugins.len(), 1);
                     """,
                 )
+
+                unitTest(
+                    "builder_from_config_bag",
+                    """
+                    use aws_smithy_runtime::client::retries::RetryPartition;
+                    use aws_smithy_types::config_bag::ConfigBag;
+                    use aws_smithy_types::config_bag::Layer;
+                    use aws_smithy_types::retry::RetryConfig;
+                    use aws_smithy_types::timeout::TimeoutConfig;
+
+                    let mut layer = Layer::new("test");
+                    layer.store_put(crate::config::ConfigField(0));
+                    layer.store_put(RetryConfig::disabled());
+                    layer.store_put(crate::config::StalledStreamProtectionConfig::disabled());
+                    layer.store_put(TimeoutConfig::builder().build());
+                    layer.store_put(RetryPartition::new("test"));
+
+                    let config_bag = ConfigBag::of_layers(vec![layer]);
+                    let builder = crate::config::Builder::from_config_bag(&config_bag);
+                    let config = builder.build();
+
+                    assert_eq!(config.config_field(), 0);
+                    assert!(config.retry_config().is_some());
+                    assert!(config.stalled_stream_protection().is_some());
+                    assert!(config.timeout_config().is_some());
+                    assert!(config.retry_partition().is_some());
+                    """,
+                )
             }
         }
     }

From 573ef36a951c22ec32b0d0e93db64636b5a3724e Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Fri, 9 Feb 2024 17:12:54 -0600
Subject: [PATCH 21/29] Add `TODO` to make `sign_http_request` user-friendly

---
 aws/rust-runtime/aws-runtime/src/auth/sigv4.rs | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/aws/rust-runtime/aws-runtime/src/auth/sigv4.rs b/aws/rust-runtime/aws-runtime/src/auth/sigv4.rs
index c422a86a78..4330c72dfa 100644
--- a/aws/rust-runtime/aws-runtime/src/auth/sigv4.rs
+++ b/aws/rust-runtime/aws-runtime/src/auth/sigv4.rs
@@ -148,6 +148,10 @@ impl SigV4Signer {
     ///
     /// This is a helper used by [`Sign::sign_http_request`] and will be useful if calling code
     /// needs to pass a configured `settings`.
+    ///
+    /// TODO(S3Express): Make this method more user friendly, possibly returning a builder
+    ///  instead of taking these input parameters. The builder will have a `sign` method that
+    ///  does what this method body currently does.
     pub fn sign_http_request(
         &self,
         request: &mut HttpRequest,

From 457f6b8fb76ff2b7e69b3271e24c47d6a5d361a9 Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Fri, 9 Feb 2024 17:25:33 -0600
Subject: [PATCH 22/29] Add a reference to docs for `IdentityCacheLocation`

This commit addresses https://github.com/smithy-lang/smithy-rs/pull/3386#discussion_r1483731849
---
 rust-runtime/aws-smithy-runtime-api/src/client/identity.rs | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/rust-runtime/aws-smithy-runtime-api/src/client/identity.rs b/rust-runtime/aws-smithy-runtime-api/src/client/identity.rs
index c6a0a30c56..2671a883a0 100644
--- a/rust-runtime/aws-smithy-runtime-api/src/client/identity.rs
+++ b/rust-runtime/aws-smithy-runtime-api/src/client/identity.rs
@@ -163,7 +163,8 @@ pub trait ResolveIdentity: Send + Sync + Debug {
     /// Returns the location of an identity cache associated with this identity resolver.
     ///
     /// By default, identity resolvers will use the identity cache stored in runtime components.
-    /// Implementing types can change the cache location if they want to.
+    /// Implementing types can change the cache location if they want to. Refer to [`IdentityCacheLocation`]
+    /// explaining why a concrete identity resolver might want to change the cache location.
     fn cache_location(&self) -> IdentityCacheLocation {
         IdentityCacheLocation::RuntimeComponents
     }

From f56923198307766393c0d9025e5ae9606481b4fd Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Fri, 9 Feb 2024 21:54:28 -0600
Subject: [PATCH 23/29] Use rustTemplate instead of rustBlockTemplate for
 readability

This commit addresses https://github.com/smithy-lang/smithy-rs/pull/3386#discussion_r1483737971
---
 .../customize/s3/S3ExpressDecorator.kt        | 27 ++++++-------------
 1 file changed, 8 insertions(+), 19 deletions(-)

diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
index cc5550615d..8529fdfc47 100644
--- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
+++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
@@ -17,7 +17,6 @@ import software.amazon.smithy.rust.codegen.client.smithy.generators.config.Confi
 import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig
 import software.amazon.smithy.rust.codegen.core.rustlang.Writable
 import software.amazon.smithy.rust.codegen.core.rustlang.rust
-import software.amazon.smithy.rust.codegen.core.rustlang.rustBlockTemplate
 import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
 import software.amazon.smithy.rust.codegen.core.rustlang.writable
 import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
@@ -165,28 +164,18 @@ class S3ExpressIdentityProviderConfig(codegenContext: ClientCodegenContext) : Co
                         *codegenScope,
                     )
 
-                    rustBlockTemplate(
+                    rustTemplate(
                         """
                         /// Sets the credentials provider for S3 Express One Zone
-                        pub fn set_express_credentials_provider(&mut self, credentials_provider: #{Option}<#{SharedCredentialsProvider}>) -> &mut Self
-                        """,
-                        *codegenScope,
-                    ) {
-                        rustBlockTemplate(
-                            """
-                            if let #{Some}(credentials_provider) = credentials_provider
-                            """,
-                            *codegenScope,
-                        ) {
-                            rustTemplate(
-                                """
+                        pub fn set_express_credentials_provider(&mut self, credentials_provider: #{Option}<#{SharedCredentialsProvider}>) -> &mut Self {
+                            if let #{Some}(credentials_provider) = credentials_provider {
                                 self.runtime_components.set_identity_resolver(#{S3_EXPRESS_SCHEME_ID}, credentials_provider);
-                                """,
-                                *codegenScope,
-                            )
+                            }
+                            self
                         }
-                        rust("self")
-                    }
+                        """,
+                        *codegenScope,
+                    )
                 }
 
                 else -> emptySection

From c3d754f7b458414b78e43a55b1fff6837c13d6d2 Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Fri, 9 Feb 2024 22:15:34 -0600
Subject: [PATCH 24/29] Exclude `s3_express` from `aws-inlineable`'s module
 tree

---
 aws/rust-runtime/aws-inlineable/src/lib.rs | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/aws/rust-runtime/aws-inlineable/src/lib.rs b/aws/rust-runtime/aws-inlineable/src/lib.rs
index 91811be46a..88459ef03d 100644
--- a/aws/rust-runtime/aws-inlineable/src/lib.rs
+++ b/aws/rust-runtime/aws-inlineable/src/lib.rs
@@ -31,9 +31,10 @@ pub mod presigning;
 /// Presigning interceptors
 pub mod presigning_interceptors;
 
-/// Supporting types for S3 Express.
-#[allow(dead_code)]
-pub mod s3_express;
+// This module uses module paths that assume the target crate to which it is copied, e.g.
+// `crate::config::endpoint::Params`. If included into `aws-inlineable`, this module would
+// fail to compile.
+// pub mod s3_express;
 
 /// Special logic for extracting request IDs from S3's responses.
 #[allow(dead_code)]

From 3233dbe2b4c37187d81b5972965be6686ab4839f Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Fri, 9 Feb 2024 22:42:00 -0600
Subject: [PATCH 25/29] Add placeholder types for S3 Express and enable control
 flow to be redirected for S3 Express use case (#3386)

## Motivation and Context
This PR is the first in the series to support the S3 Express feature in
the Rust SDK. The work will be done in the feature branch, and once it
is code complete, the branch will be merged to main.

## Description
This PR adds placeholder types for S3 Express and enables control flow
to be redirected for S3 Express use case. For instance, if we run the
following example code against a generated SDK from this PR:
```rust
let shared_config = aws_config::from_env().region(aws_sdk_s3::config::Region::new("us-east-1")).load().await;
let client = aws_sdk_s3::Client::new(&shared_config);
client.list_objects_v2().bucket("testbucket--use1-az4--x-s3";).send().await.unwrap();
```
it will end up
```
thread 's3_express' panicked at 'not yet implemented', /Users/awsaito/src/smithy-rs/aws/sdk/build/aws-sdk/sdk/s3/src/s3_express.rs:104:13
```
which points to
```
impl ProvideCredentials for DefaultS3ExpressIdentityProvider {
    fn provide_credentials<'a>(&'a self) -> aws_credential_types::provider::future::ProvideCredentials<'a>
    where
        Self: 'a,
    {
        todo!() <---
    }
}
```

### Implementation decisions
- `DefaultS3ExpressIdentityProvider` has an accompanying identity cache.
That identity cache cannot be configured by customers so it makes sense
for the provider itself to internally own it. In that case, we do NOT
want to use the identity cache stored in `RuntimeComponents`, since it
interferes with the S3 Express's caching policy. To that end, I added an
enum `CacheLocation` to `SharedIdentityResolver` (it already had the
`cache_partition` field so it was kind of aware of caching).
- Two reasons why `CacheLocation` is added to `SharedIdentityResolver`,
but not to individual, concrete `IdentityResolver`s. One is
`SharedIdentityResolver` was already cache aware, as mentioned above.
The other is that it is more flexible that way; The cache location is
not tied to a type of identity resolver, but we can select it when
creating a `SharedIdentityResolver`.
- I considered but did not add a field `cacheable` to `Identity` since I
wanted to keep `Identity` as plain data, keeping the concept of
"caching" somewhere outside.
- I've added a separate `Config` method,
`set_express_credentials_provider`, to override credentials provider for
S3 Express. There are other SDKs (e.g.
[Ruby](https://www.rubydoc.info/gems/aws-sdk-s3/Aws/S3/Client)) that
follow this style and it makes it clear to the customers that this is
the method to use when overriding the express credentials provider. The
existing `set_credentials_provider`, given its input type, cannot tell
whether a passed-in credentials provider is for a regular `sigv4` or for
S3 Express.

## Testing
Only verified that control flow could be altered for an S3 Express use
case, as shown above. Further testing will be added in subsequent PRs.

## Checklist
I am planning to include in `CHANGELOG.next.toml` a user guide for S3
Express once the feature branch `ysaito/s3express` is ready to be merged
to main.

----

_By submitting this pull request, I confirm that you can use, modify,
copy, and redistribute this contribution, under the terms of your
choice._

---------

Co-authored-by: John DiSanti <jdisanti@amazon.com>
Co-authored-by: AWS SDK Rust Bot <aws-sdk-rust-primary@amazon.com>
Co-authored-by: AWS SDK Rust Bot <97246200+aws-sdk-rust-ci@users.noreply.github.com>
Co-authored-by: Zelda Hessler <zhessler@amazon.com>
---
 aws/rust-runtime/aws-inlineable/src/lib.rs    |   5 +
 .../aws-inlineable/src/s3_express.rs          | 125 ++++++++++++
 .../smithy/rustsdk/AwsCodegenDecorator.kt     |   2 +
 .../customize/s3/S3ExpressDecorator.kt        | 184 ++++++++++++++++++
 .../endpoints/OperationInputTestGenerator.kt  |   8 +
 .../ServiceRuntimePluginGenerator.kt          |   8 +
 .../src/client/identity.rs                    |  28 +++
 .../src/client/orchestrator/auth.rs           |  12 +-
 8 files changed, 370 insertions(+), 2 deletions(-)
 create mode 100644 aws/rust-runtime/aws-inlineable/src/s3_express.rs
 create mode 100644 aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt

diff --git a/aws/rust-runtime/aws-inlineable/src/lib.rs b/aws/rust-runtime/aws-inlineable/src/lib.rs
index 0ae9627703..88459ef03d 100644
--- a/aws/rust-runtime/aws-inlineable/src/lib.rs
+++ b/aws/rust-runtime/aws-inlineable/src/lib.rs
@@ -31,6 +31,11 @@ pub mod presigning;
 /// Presigning interceptors
 pub mod presigning_interceptors;
 
+// This module uses module paths that assume the target crate to which it is copied, e.g.
+// `crate::config::endpoint::Params`. If included into `aws-inlineable`, this module would
+// fail to compile.
+// pub mod s3_express;
+
 /// Special logic for extracting request IDs from S3's responses.
 #[allow(dead_code)]
 pub mod s3_request_id;
diff --git a/aws/rust-runtime/aws-inlineable/src/s3_express.rs b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
new file mode 100644
index 0000000000..76b8a95093
--- /dev/null
+++ b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
@@ -0,0 +1,125 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+/// Supporting code for S3 Express auth
+pub(crate) mod auth {
+    use aws_smithy_runtime_api::box_error::BoxError;
+    use aws_smithy_runtime_api::client::auth::{
+        AuthScheme, AuthSchemeEndpointConfig, AuthSchemeId, Sign,
+    };
+    use aws_smithy_runtime_api::client::identity::{Identity, SharedIdentityResolver};
+    use aws_smithy_runtime_api::client::orchestrator::HttpRequest;
+    use aws_smithy_runtime_api::client::runtime_components::{
+        GetIdentityResolver, RuntimeComponents,
+    };
+    use aws_smithy_types::config_bag::ConfigBag;
+
+    /// Auth scheme ID for S3 Express.
+    pub(crate) const SCHEME_ID: AuthSchemeId = AuthSchemeId::new("sigv4-s3express");
+
+    /// S3 Express auth scheme.
+    #[derive(Debug, Default)]
+    pub(crate) struct S3ExpressAuthScheme {
+        signer: S3ExpressSigner,
+    }
+
+    impl S3ExpressAuthScheme {
+        /// Creates a new `S3ExpressAuthScheme`.
+        pub(crate) fn new() -> Self {
+            Default::default()
+        }
+    }
+
+    impl AuthScheme for S3ExpressAuthScheme {
+        fn scheme_id(&self) -> AuthSchemeId {
+            SCHEME_ID
+        }
+
+        fn identity_resolver(
+            &self,
+            identity_resolvers: &dyn GetIdentityResolver,
+        ) -> Option<SharedIdentityResolver> {
+            identity_resolvers.identity_resolver(self.scheme_id())
+        }
+
+        fn signer(&self) -> &dyn Sign {
+            &self.signer
+        }
+    }
+
+    /// S3 Express signer.
+    #[derive(Debug, Default)]
+    pub(crate) struct S3ExpressSigner;
+
+    impl Sign for S3ExpressSigner {
+        fn sign_http_request(
+            &self,
+            _request: &mut HttpRequest,
+            _identity: &Identity,
+            _auth_scheme_endpoint_config: AuthSchemeEndpointConfig<'_>,
+            _runtime_components: &RuntimeComponents,
+            _config_bag: &ConfigBag,
+        ) -> Result<(), BoxError> {
+            todo!()
+        }
+    }
+}
+
+/// Supporting code for S3 Express identity cache
+pub(crate) mod identity_cache {
+    /// The caching implementation for S3 Express identity.
+    ///
+    /// While customers can either disable S3 Express itself or provide a custom S3 Express identity
+    /// provider, configuring S3 Express identity cache is not supported. Thus, this is _the_
+    /// implementation of S3 Express identity cache.
+    #[derive(Debug)]
+    pub(crate) struct S3ExpressIdentityCache;
+}
+
+/// Supporting code for S3 Express identity provider
+pub(crate) mod identity_provider {
+    use crate::s3_express::identity_cache::S3ExpressIdentityCache;
+    use aws_smithy_runtime_api::client::identity::{
+        IdentityCacheLocation, IdentityFuture, ResolveIdentity,
+    };
+    use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;
+    use aws_smithy_types::config_bag::ConfigBag;
+
+    #[derive(Debug)]
+    pub(crate) struct DefaultS3ExpressIdentityProvider {
+        _cache: S3ExpressIdentityCache,
+    }
+
+    #[derive(Default)]
+    pub(crate) struct Builder;
+
+    impl DefaultS3ExpressIdentityProvider {
+        pub(crate) fn builder() -> Builder {
+            Builder
+        }
+    }
+
+    impl Builder {
+        pub(crate) fn build(self) -> DefaultS3ExpressIdentityProvider {
+            DefaultS3ExpressIdentityProvider {
+                _cache: S3ExpressIdentityCache,
+            }
+        }
+    }
+
+    impl ResolveIdentity for DefaultS3ExpressIdentityProvider {
+        fn resolve_identity<'a>(
+            &'a self,
+            _runtime_components: &'a RuntimeComponents,
+            _config_bag: &'a ConfigBag,
+        ) -> IdentityFuture<'a> {
+            todo!()
+        }
+
+        fn cache_location(&self) -> IdentityCacheLocation {
+            IdentityCacheLocation::IdentityResolver
+        }
+    }
+}
diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt
index 3bc616a9b8..2c13e4b2b7 100644
--- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt
+++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt
@@ -18,6 +18,7 @@ import software.amazon.smithy.rustsdk.customize.glacier.GlacierDecorator
 import software.amazon.smithy.rustsdk.customize.onlyApplyTo
 import software.amazon.smithy.rustsdk.customize.route53.Route53Decorator
 import software.amazon.smithy.rustsdk.customize.s3.S3Decorator
+import software.amazon.smithy.rustsdk.customize.s3.S3ExpressDecorator
 import software.amazon.smithy.rustsdk.customize.s3.S3ExtendedRequestIdDecorator
 import software.amazon.smithy.rustsdk.customize.s3control.S3ControlDecorator
 import software.amazon.smithy.rustsdk.customize.sso.SSODecorator
@@ -64,6 +65,7 @@ val DECORATORS: List<ClientCodegenDecorator> =
         Route53Decorator().onlyApplyTo("com.amazonaws.route53#AWSDnsV20130401"),
         "com.amazonaws.s3#AmazonS3".applyDecorators(
             S3Decorator(),
+            S3ExpressDecorator(),
             S3ExtendedRequestIdDecorator(),
         ),
         S3ControlDecorator().onlyApplyTo("com.amazonaws.s3control#AWSS3ControlServiceV20180820"),
diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
new file mode 100644
index 0000000000..8529fdfc47
--- /dev/null
+++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/customize/s3/S3ExpressDecorator.kt
@@ -0,0 +1,184 @@
+/*
+ * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+package software.amazon.smithy.rustsdk.customize.s3
+
+import software.amazon.smithy.aws.traits.auth.SigV4Trait
+import software.amazon.smithy.model.shapes.OperationShape
+import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
+import software.amazon.smithy.rust.codegen.client.smithy.configReexport
+import software.amazon.smithy.rust.codegen.client.smithy.customize.AuthSchemeOption
+import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator
+import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginCustomization
+import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginSection
+import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ConfigCustomization
+import software.amazon.smithy.rust.codegen.client.smithy.generators.config.ServiceConfig
+import software.amazon.smithy.rust.codegen.core.rustlang.Writable
+import software.amazon.smithy.rust.codegen.core.rustlang.rust
+import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
+import software.amazon.smithy.rust.codegen.core.rustlang.writable
+import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType
+import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType.Companion.preludeScope
+import software.amazon.smithy.rustsdk.AwsRuntimeType
+import software.amazon.smithy.rustsdk.InlineAwsDependency
+
+class S3ExpressDecorator : ClientCodegenDecorator {
+    override val name: String = "S3ExpressDecorator"
+    override val order: Byte = 0
+
+    private fun sigv4S3Express() =
+        writable {
+            rust(
+                "#T",
+                RuntimeType.forInlineDependency(
+                    InlineAwsDependency.forRustFile("s3_express"),
+                ).resolve("auth::SCHEME_ID"),
+            )
+        }
+
+    override fun authOptions(
+        codegenContext: ClientCodegenContext,
+        operationShape: OperationShape,
+        baseAuthSchemeOptions: List<AuthSchemeOption>,
+    ): List<AuthSchemeOption> =
+        baseAuthSchemeOptions +
+            AuthSchemeOption.StaticAuthSchemeOption(
+                SigV4Trait.ID,
+                listOf(sigv4S3Express()),
+            )
+
+    override fun serviceRuntimePluginCustomizations(
+        codegenContext: ClientCodegenContext,
+        baseCustomizations: List<ServiceRuntimePluginCustomization>,
+    ): List<ServiceRuntimePluginCustomization> =
+        baseCustomizations + listOf(S3ExpressServiceRuntimePluginCustomization(codegenContext))
+
+    override fun configCustomizations(
+        codegenContext: ClientCodegenContext,
+        baseCustomizations: List<ConfigCustomization>,
+    ): List<ConfigCustomization> = baseCustomizations + listOf(S3ExpressIdentityProviderConfig(codegenContext))
+}
+
+private class S3ExpressServiceRuntimePluginCustomization(codegenContext: ClientCodegenContext) :
+    ServiceRuntimePluginCustomization() {
+    private val runtimeConfig = codegenContext.runtimeConfig
+    private val codegenScope by lazy {
+        arrayOf(
+            "DefaultS3ExpressIdentityProvider" to
+                RuntimeType.forInlineDependency(
+                    InlineAwsDependency.forRustFile("s3_express"),
+                ).resolve("identity_provider::DefaultS3ExpressIdentityProvider"),
+            "IdentityCacheLocation" to
+                RuntimeType.smithyRuntimeApiClient(runtimeConfig)
+                    .resolve("client::identity::IdentityCacheLocation"),
+            "S3ExpressAuthScheme" to
+                RuntimeType.forInlineDependency(
+                    InlineAwsDependency.forRustFile("s3_express"),
+                ).resolve("auth::S3ExpressAuthScheme"),
+            "S3_EXPRESS_SCHEME_ID" to
+                RuntimeType.forInlineDependency(
+                    InlineAwsDependency.forRustFile("s3_express"),
+                ).resolve("auth::SCHEME_ID"),
+            "SharedAuthScheme" to
+                RuntimeType.smithyRuntimeApiClient(runtimeConfig)
+                    .resolve("client::auth::SharedAuthScheme"),
+            "SharedCredentialsProvider" to
+                configReexport(
+                    AwsRuntimeType.awsCredentialTypes(runtimeConfig)
+                        .resolve("provider::SharedCredentialsProvider"),
+                ),
+            "SharedIdentityResolver" to
+                RuntimeType.smithyRuntimeApiClient(runtimeConfig)
+                    .resolve("client::identity::SharedIdentityResolver"),
+        )
+    }
+
+    override fun section(section: ServiceRuntimePluginSection): Writable =
+        writable {
+            when (section) {
+                is ServiceRuntimePluginSection.RegisterRuntimeComponents -> {
+                    section.registerAuthScheme(this) {
+                        rustTemplate(
+                            "#{SharedAuthScheme}::new(#{S3ExpressAuthScheme}::new())",
+                            *codegenScope,
+                        )
+                    }
+
+                    section.registerIdentityResolver(
+                        this,
+                        writable {
+                            rustTemplate("#{S3_EXPRESS_SCHEME_ID}", *codegenScope)
+                        },
+                        writable {
+                            rustTemplate("#{DefaultS3ExpressIdentityProvider}::builder().build()", *codegenScope)
+                        },
+                    )
+                }
+
+                else -> {}
+            }
+        }
+}
+
+class S3ExpressIdentityProviderConfig(codegenContext: ClientCodegenContext) : ConfigCustomization() {
+    private val runtimeConfig = codegenContext.runtimeConfig
+    private val codegenScope =
+        arrayOf(
+            *preludeScope,
+            "IdentityCacheLocation" to
+                RuntimeType.smithyRuntimeApiClient(runtimeConfig)
+                    .resolve("client::identity::IdentityCacheLocation"),
+            "ProvideCredentials" to
+                configReexport(
+                    AwsRuntimeType.awsCredentialTypes(runtimeConfig)
+                        .resolve("provider::ProvideCredentials"),
+                ),
+            "SharedCredentialsProvider" to
+                configReexport(
+                    AwsRuntimeType.awsCredentialTypes(runtimeConfig)
+                        .resolve("provider::SharedCredentialsProvider"),
+                ),
+            "SharedIdentityResolver" to
+                RuntimeType.smithyRuntimeApiClient(runtimeConfig)
+                    .resolve("client::identity::SharedIdentityResolver"),
+            "S3_EXPRESS_SCHEME_ID" to
+                RuntimeType.forInlineDependency(
+                    InlineAwsDependency.forRustFile("s3_express"),
+                ).resolve("auth::SCHEME_ID"),
+        )
+
+    override fun section(section: ServiceConfig) =
+        writable {
+            when (section) {
+                ServiceConfig.BuilderImpl -> {
+                    rustTemplate(
+                        """
+                        /// Sets the credentials provider for S3 Express One Zone
+                        pub fn express_credentials_provider(mut self, credentials_provider: impl #{ProvideCredentials} + 'static) -> Self {
+                            self.set_express_credentials_provider(#{Some}(#{SharedCredentialsProvider}::new(credentials_provider)));
+                            self
+                        }
+                        """,
+                        *codegenScope,
+                    )
+
+                    rustTemplate(
+                        """
+                        /// Sets the credentials provider for S3 Express One Zone
+                        pub fn set_express_credentials_provider(&mut self, credentials_provider: #{Option}<#{SharedCredentialsProvider}>) -> &mut Self {
+                            if let #{Some}(credentials_provider) = credentials_provider {
+                                self.runtime_components.set_identity_resolver(#{S3_EXPRESS_SCHEME_ID}, credentials_provider);
+                            }
+                            self
+                        }
+                        """,
+                        *codegenScope,
+                    )
+                }
+
+                else -> emptySection
+            }
+        }
+}
diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/OperationInputTestGenerator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/OperationInputTestGenerator.kt
index 5bcc870ae5..544d30ea8f 100644
--- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/OperationInputTestGenerator.kt
+++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/endpoints/OperationInputTestGenerator.kt
@@ -126,9 +126,17 @@ class OperationInputTestGenerator(_ctx: ClientCodegenContext, private val test:
     private val model = ctx.model
     private val instantiator = ClientInstantiator(ctx)
 
+    /** tests using S3 Express bucket names need to be disabled until the implementation is in place **/
+    private fun EndpointTestCase.isSigV4S3Express() =
+        expect.endpoint.orNull()?.properties?.get("authSchemes")?.asArrayNode()?.orNull()
+            ?.map { it.expectObjectNode().expectStringMember("name").value }?.contains("sigv4-s3express") == true
+
     fun generateInput(testOperationInput: EndpointTestOperationInput) =
         writable {
             val operationName = testOperationInput.operationName.toSnakeCase()
+            if (test.isSigV4S3Express()) {
+                Attribute.shouldPanic("not yet implemented").render(this)
+            }
             tokioTest(safeName("operation_input_test_$operationName")) {
                 rustTemplate(
                     """
diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt
index 66095c1555..699e5bff19 100644
--- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt
+++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/ServiceRuntimePluginGenerator.kt
@@ -69,6 +69,14 @@ sealed class ServiceRuntimePluginSection(name: String) : Section(name) {
         ) {
             writer.rust("runtime_components.push_retry_classifier(#T);", classifier)
         }
+
+        fun registerIdentityResolver(
+            writer: RustWriter,
+            schemeId: Writable,
+            identityResolver: Writable,
+        ) {
+            writer.rust("runtime_components.set_identity_resolver(#T, #T);", schemeId, identityResolver)
+        }
     }
 }
 typealias ServiceRuntimePluginCustomization = NamedCustomization<ServiceRuntimePluginSection>
diff --git a/rust-runtime/aws-smithy-runtime-api/src/client/identity.rs b/rust-runtime/aws-smithy-runtime-api/src/client/identity.rs
index f0e972675a..2671a883a0 100644
--- a/rust-runtime/aws-smithy-runtime-api/src/client/identity.rs
+++ b/rust-runtime/aws-smithy-runtime-api/src/client/identity.rs
@@ -159,6 +159,30 @@ pub trait ResolveIdentity: Send + Sync + Debug {
     fn fallback_on_interrupt(&self) -> Option<Identity> {
         None
     }
+
+    /// Returns the location of an identity cache associated with this identity resolver.
+    ///
+    /// By default, identity resolvers will use the identity cache stored in runtime components.
+    /// Implementing types can change the cache location if they want to. Refer to [`IdentityCacheLocation`]
+    /// explaining why a concrete identity resolver might want to change the cache location.
+    fn cache_location(&self) -> IdentityCacheLocation {
+        IdentityCacheLocation::RuntimeComponents
+    }
+}
+
+/// Cache location for identity caching.
+///
+/// Identities are usually cached in the identity cache owned by [`RuntimeComponents`]. However,
+/// we do have identities whose caching mechanism is internally managed by their identity resolver,
+/// in which case we want to avoid the `RuntimeComponents`-owned identity cache interfering with
+/// the internal caching policy.
+#[non_exhaustive]
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub enum IdentityCacheLocation {
+    /// Indicates the identity cache is owned by [`RuntimeComponents`].
+    RuntimeComponents,
+    /// Indicates the identity cache is internally managed by the identity resolver.
+    IdentityResolver,
 }
 
 /// Container for a shared identity resolver.
@@ -194,6 +218,10 @@ impl ResolveIdentity for SharedIdentityResolver {
     ) -> IdentityFuture<'a> {
         self.inner.resolve_identity(runtime_components, config_bag)
     }
+
+    fn cache_location(&self) -> IdentityCacheLocation {
+        self.inner.cache_location()
+    }
 }
 
 impl_shared_conversions!(convert SharedIdentityResolver from ResolveIdentity using SharedIdentityResolver::new);
diff --git a/rust-runtime/aws-smithy-runtime/src/client/orchestrator/auth.rs b/rust-runtime/aws-smithy-runtime/src/client/orchestrator/auth.rs
index 98a39a9a43..0bf5ecf1a7 100644
--- a/rust-runtime/aws-smithy-runtime/src/client/orchestrator/auth.rs
+++ b/rust-runtime/aws-smithy-runtime/src/client/orchestrator/auth.rs
@@ -4,12 +4,14 @@
  */
 
 use crate::client::auth::no_auth::NO_AUTH_SCHEME_ID;
+use crate::client::identity::IdentityCache;
 use aws_smithy_runtime_api::box_error::BoxError;
 use aws_smithy_runtime_api::client::auth::{
     AuthScheme, AuthSchemeEndpointConfig, AuthSchemeId, AuthSchemeOptionResolverParams,
     ResolveAuthSchemeOptions,
 };
-use aws_smithy_runtime_api::client::identity::ResolveCachedIdentity;
+use aws_smithy_runtime_api::client::identity::ResolveIdentity;
+use aws_smithy_runtime_api::client::identity::{IdentityCacheLocation, ResolveCachedIdentity};
 use aws_smithy_runtime_api::client::interceptors::context::InterceptorContext;
 use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;
 use aws_smithy_types::config_bag::ConfigBag;
@@ -135,7 +137,13 @@ pub(super) async fn orchestrate_auth(
         if let Some(auth_scheme) = runtime_components.auth_scheme(scheme_id) {
             // Use the resolved auth scheme to resolve an identity
             if let Some(identity_resolver) = auth_scheme.identity_resolver(runtime_components) {
-                let identity_cache = runtime_components.identity_cache();
+                let identity_cache = if identity_resolver.cache_location()
+                    == IdentityCacheLocation::RuntimeComponents
+                {
+                    runtime_components.identity_cache()
+                } else {
+                    IdentityCache::no_cache()
+                };
                 let signer = auth_scheme.signer();
                 trace!(
                     auth_scheme = ?auth_scheme,

From d2354bd5133897b68435d8120e4f6fd4735caed8 Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Mon, 12 Feb 2024 11:59:23 -0600
Subject: [PATCH 26/29] Anonymize tokens in S3 Express recording test

---
 .../s3/tests/data/express/list-objects-v2.json         | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/aws/sdk/integration-tests/s3/tests/data/express/list-objects-v2.json b/aws/sdk/integration-tests/s3/tests/data/express/list-objects-v2.json
index 6d04afe1c8..9bbc52fe05 100644
--- a/aws/sdk/integration-tests/s3/tests/data/express/list-objects-v2.json
+++ b/aws/sdk/integration-tests/s3/tests/data/express/list-objects-v2.json
@@ -20,7 +20,7 @@
                 "20090213T233130Z"
               ],
               "authorization": [
-                "AWS4-HMAC-SHA256 Credential=ANOTREAL/20090213/us-west-2/s3express/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-create-session-mode;x-amz-date;x-amz-user-agent, Signature=4d44fb95628114b17a0676e2da758dee74f8a0337a3f0183e5b91e4fea6d9303"
+                "AWS4-HMAC-SHA256 Credential=ANOTREAL/20090213/us-west-2/s3express/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-create-session-mode;x-amz-date;x-amz-user-agent, Signature=1f63e649e5433837f97c037489613e036b98bff8cdf8d7bcf24b770d041ac0b9"
               ],
               "user-agent": [
                 "aws-sdk-rust/0.123.test os/windows/XPSP3 lang/rust/1.50.0"
@@ -61,7 +61,7 @@
                   "application/xml"
                 ],
                 "content-length": [
-                  "1035"
+                  "333"
                 ],
                 "server": [
                   "AmazonS3"
@@ -77,7 +77,7 @@
       "action": {
         "Data": {
           "data": {
-            "Utf8": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CreateSessionResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><Credentials><SessionToken>AgAAAGxnCC7+1qgZF9Zo1aMcI+JZNlNSXzzvpCif4IsEAAAAAAAAADAoC5fHAQAAAAAAAK5b/HX2sWg7Eb+jLXyaCWq0KEMdETvdCBl/bqHtnVkbjoT2p4K7FXiJy7J6VBuCvQhcIlnINa6ed7GF2xgzFNyENQkps2RpLj1lEqWmPAtnoeQqWqYSPwnKh+TVL4vGXfV9mFEeZMEW8eP7o/BWRtYg2ERp3+vUGwRhFRXXIjwTrKe76U/l7mSK79xRV6nMxKJi4/tNG98GKX7FGdEU/dVKEhpe1mRvltkVyA9KnkIwvysLsQLN+rUsbmPhvMManqGCSWqpjbbETp2RUVbg3Vxa9bvlzfW8+BR0CdrZ1QUi5NdwV6gAaJZ8TzNfdvwZJy4asC6ay3t6VBVFtcV+yfWdNx5pHOnxm7siiIbW8iv0jZzuJCzk36QoOAP8Tt3bVOJ592sgkt/ZF1LcmPC1BCXzwG7uuexPdOuoG3WbkEKQxv7Qa84JooPQjaWSHVgQONdLMSSCXjuPn9YAeTyeuOkpARBHlf+KT0D72ISLvZFHn/j/gxnZww2hJUoKpM5obWdbij4yNH+DW8FHmAnRf5DWTBSLWk6SFpE7UvUCRb3LqxAuu0SoaRmdJACtBcKAIgr2HiPwULHYbOlkcKcj5K5W1UA9ssvd</SessionToken><SecretAccessKey>HR6zWlAl1yjsuP8jo/Rw6aqaooVeDeOM2EMn35/b</SecretAccessKey><AccessKeyId>CT7ODKCW3E7XYBDHMKLEOIBWIA</AccessKeyId><Expiration>2024-01-29T18:53:01Z</Expiration></Credentials></CreateSessionResult>"
+            "Utf8": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CreateSessionResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><Credentials><SessionToken>TESTSESSIONTOKEN</SessionToken><SecretAccessKey>TESTSECRETKEY</SecretAccessKey><AccessKeyId>ASIARTESTID</AccessKeyId><Expiration>2024-01-29T18:53:01Z</Expiration></Credentials></CreateSessionResult>"
           },
           "direction": "Response"
         }
@@ -100,7 +100,7 @@
             "uri": "https://s3express-test-bucket--usw2-az1--x-s3.s3express-usw2-az1.us-west-2.amazonaws.com/?list-type=2",
             "headers": {
               "authorization": [
-                "AWS4-HMAC-SHA256 Credential=CT7ODKCW3E7XYBDHMKLEOIBWIA/20090213/us-west-2/s3express/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-s3session-token;x-amz-user-agent, Signature=12751fd6558c96b00f3dd624602b0f89e969a8885bada0f5e8b251953ef4e203"
+                "AWS4-HMAC-SHA256 Credential=ASIARTESTID/20090213/us-west-2/s3express/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-s3session-token;x-amz-user-agent, Signature=d1765aa7ec005607ba94fdda08c6739228d5ee14eb8316e80264c35649661a19"
               ],
               "x-amz-date": [
                 "20090213T233130Z"
@@ -112,7 +112,7 @@
                 "aws-sdk-rust/0.123.test api/test-service/0.123 os/windows/XPSP3 lang/rust/1.50.0"
               ],
               "x-amz-s3session-token": [
-                "AgAAAGxnCC7+1qgZF9Zo1aMcI+JZNlNSXzzvpCif4IsEAAAAAAAAADAoC5fHAQAAAAAAAK5b/HX2sWg7Eb+jLXyaCWq0KEMdETvdCBl/bqHtnVkbjoT2p4K7FXiJy7J6VBuCvQhcIlnINa6ed7GF2xgzFNyENQkps2RpLj1lEqWmPAtnoeQqWqYSPwnKh+TVL4vGXfV9mFEeZMEW8eP7o/BWRtYg2ERp3+vUGwRhFRXXIjwTrKe76U/l7mSK79xRV6nMxKJi4/tNG98GKX7FGdEU/dVKEhpe1mRvltkVyA9KnkIwvysLsQLN+rUsbmPhvMManqGCSWqpjbbETp2RUVbg3Vxa9bvlzfW8+BR0CdrZ1QUi5NdwV6gAaJZ8TzNfdvwZJy4asC6ay3t6VBVFtcV+yfWdNx5pHOnxm7siiIbW8iv0jZzuJCzk36QoOAP8Tt3bVOJ592sgkt/ZF1LcmPC1BCXzwG7uuexPdOuoG3WbkEKQxv7Qa84JooPQjaWSHVgQONdLMSSCXjuPn9YAeTyeuOkpARBHlf+KT0D72ISLvZFHn/j/gxnZww2hJUoKpM5obWdbij4yNH+DW8FHmAnRf5DWTBSLWk6SFpE7UvUCRb3LqxAuu0SoaRmdJACtBcKAIgr2HiPwULHYbOlkcKcj5K5W1UA9ssvd"
+                "TESTSESSIONTOKEN"
               ],
               "user-agent": [
                 "aws-sdk-rust/0.123.test os/windows/XPSP3 lang/rust/1.50.0"

From 027c2cdfd96e652785142761bb28b0966f310d78 Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Wed, 14 Feb 2024 15:07:23 -0600
Subject: [PATCH 27/29] Remove `From<RuntimeComponents> for
 RuntimeComponentsBuilder`

This commit addresses https://github.com/smithy-lang/smithy-rs/pull/3388#discussion_r1486625277
---
 .../src/client/runtime_components.rs          | 20 -------------------
 1 file changed, 20 deletions(-)

diff --git a/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs b/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs
index c63c37d436..5d86dd5405 100644
--- a/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs
+++ b/rust-runtime/aws-smithy-runtime-api/src/client/runtime_components.rs
@@ -380,26 +380,6 @@ declare_runtime_components! {
     }
 }
 
-impl From<RuntimeComponents> for RuntimeComponentsBuilder {
-    fn from(rc: RuntimeComponents) -> Self {
-        RuntimeComponentsBuilder {
-            builder_name: "converted from RuntimeComponents",
-            auth_scheme_option_resolver: Some(rc.auth_scheme_option_resolver),
-            http_client: rc.http_client,
-            endpoint_resolver: Some(rc.endpoint_resolver),
-            auth_schemes: rc.auth_schemes,
-            identity_cache: Some(rc.identity_cache),
-            identity_resolvers: Some(rc.identity_resolvers),
-            interceptors: rc.interceptors,
-            retry_classifiers: rc.retry_classifiers,
-            retry_strategy: Some(rc.retry_strategy),
-            time_source: rc.time_source,
-            sleep_impl: rc.sleep_impl,
-            config_validators: rc.config_validators,
-        }
-    }
-}
-
 impl RuntimeComponents {
     /// Returns a builder for runtime components.
     pub fn builder(name: &'static str) -> RuntimeComponentsBuilder {

From 830ef0283fb8243311b607ba443bddbacaf3f5ad Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Thu, 15 Feb 2024 16:20:33 -0600
Subject: [PATCH 28/29] Add a setting to replace session token name

This commit addresses:
https://github.com/smithy-lang/smithy-rs/pull/3388#discussion_r1486609370
https://github.com/smithy-lang/smithy-rs/pull/3388#discussion_r1486609590
https://github.com/smithy-lang/smithy-rs/pull/3388#discussion_r1486615620
---
 .../aws-inlineable/src/s3_express.rs          | 88 ++-----------------
 .../src/http_request/canonical_request.rs     | 19 ++--
 .../aws-sigv4/src/http_request/settings.rs    | 23 +----
 .../aws-sigv4/src/http_request/sign.rs        | 36 ++++----
 4 files changed, 40 insertions(+), 126 deletions(-)

diff --git a/aws/rust-runtime/aws-inlineable/src/s3_express.rs b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
index d773c71904..3388145112 100644
--- a/aws/rust-runtime/aws-inlineable/src/s3_express.rs
+++ b/aws/rust-runtime/aws-inlineable/src/s3_express.rs
@@ -5,10 +5,6 @@
 
 /// Supporting code for S3 Express auth
 pub(crate) mod auth {
-    use std::borrow::Cow;
-    use std::str::FromStr;
-
-    use aws_credential_types::Credentials;
     use aws_runtime::auth::sigv4::SigV4Signer;
     use aws_sigv4::http_request::{SignatureLocation, SigningSettings};
     use aws_smithy_runtime_api::box_error::BoxError;
@@ -71,12 +67,7 @@ pub(crate) mod auth {
             let operation_config =
                 SigV4Signer::extract_operation_config(auth_scheme_endpoint_config, config_bag)?;
             let mut settings = SigV4Signer::signing_settings(&operation_config);
-
-            let express_credentials = identity.data::<Credentials>().ok_or(
-                "wrong identity type for SigV4. Expected AWS credentials but got `{identity:?}",
-            )?;
-
-            add_token_to_request(express_credentials, request, &mut settings)?;
+            override_session_token_name(&mut settings)?;
 
             SigV4Signer.sign_http_request(
                 request,
@@ -89,80 +80,13 @@ pub(crate) mod auth {
         }
     }
 
-    fn add_token_to_request(
-        express_credentials: &Credentials,
-        request: &mut HttpRequest,
-        settings: &mut SigningSettings,
-    ) -> Result<(), BoxError> {
-        match settings.signature_location {
-            SignatureLocation::Headers => {
-                let security_token_header = Cow::Borrowed("x-amz-security-token");
-                match settings.excluded_headers.as_mut() {
-                    Some(excluded) => {
-                        excluded.push(security_token_header);
-                    }
-                    None => {
-                        settings
-                            .excluded_params
-                            .get_or_insert(vec![security_token_header]);
-                    }
-                }
-                let mut value = http::HeaderValue::from_str(
-                    express_credentials
-                        .session_token()
-                        .expect("S3 session token should be set"),
-                )
-                .unwrap();
-                value.set_sensitive(true);
-                request.headers_mut().insert(
-                    http::HeaderName::from_static("x-amz-s3session-token"),
-                    value,
-                );
-            }
-            SignatureLocation::QueryParams => {
-                let security_token_param = Cow::Borrowed("X-Amz-Security-Token");
-                match settings.excluded_params.as_mut() {
-                    Some(excluded) => {
-                        excluded.push(security_token_param);
-                    }
-                    None => {
-                        settings
-                            .excluded_params
-                            .get_or_insert(vec![security_token_param]);
-                    }
-                }
-                let uri = http::Uri::from_str(request.uri()).unwrap();
-                let mut query_params = match uri.query() {
-                    Some(query) => query.split('&').collect(),
-                    None => vec![],
-                };
-                let param = &format!(
-                    "X-Amz-S3session-Token={}",
-                    aws_smithy_http::query::fmt_string(
-                        express_credentials
-                            .session_token()
-                            .expect("S3 session token should be set")
-                    )
-                );
-                query_params.push(param);
-                let uri = http::Uri::builder()
-                    .authority(
-                        uri.authority()
-                            .ok_or("request URI should have authority set")?
-                            .clone(),
-                    )
-                    .scheme(
-                        uri.scheme()
-                            .ok_or("request URI should have scheme set")?
-                            .clone(),
-                    )
-                    .path_and_query(format!("{}?{}", uri.path(), query_params.join("&")))
-                    .build()?;
-                request.set_uri(uri)?
-            }
+    fn override_session_token_name(settings: &mut SigningSettings) -> Result<(), BoxError> {
+        let session_token_name_override = match settings.signature_location {
+            SignatureLocation::Headers => Some("x-amz-s3session-token"),
+            SignatureLocation::QueryParams => Some("X-Amz-S3session-Token"),
             _ => { return Err(BoxError::from("`SignatureLocation` adds a new variant, which needs to be handled in a separate match arm")) },
         };
-
+        settings.session_token_name_override = session_token_name_override;
         Ok(())
     }
 }
diff --git a/aws/rust-runtime/aws-sigv4/src/http_request/canonical_request.rs b/aws/rust-runtime/aws-sigv4/src/http_request/canonical_request.rs
index 43e31c0ac1..5bc088ecf5 100644
--- a/aws/rust-runtime/aws-sigv4/src/http_request/canonical_request.rs
+++ b/aws/rust-runtime/aws-sigv4/src/http_request/canonical_request.rs
@@ -250,6 +250,11 @@ impl<'a> CanonicalRequest<'a> {
 
         Self::insert_host_header(&mut canonical_headers, req.uri());
 
+        let token_header_name = params
+            .settings()
+            .session_token_name_override
+            .unwrap_or(header::X_AMZ_SECURITY_TOKEN);
+
         if params.settings().signature_location == SignatureLocation::Headers {
             let creds = params
                 .credentials()
@@ -259,7 +264,7 @@ impl<'a> CanonicalRequest<'a> {
             if let Some(security_token) = creds.session_token() {
                 let mut sec_header = HeaderValue::from_str(security_token)?;
                 sec_header.set_sensitive(true);
-                canonical_headers.insert(header::X_AMZ_SECURITY_TOKEN, sec_header);
+                canonical_headers.insert(token_header_name, sec_header);
             }
 
             if params.settings().payload_checksum_kind == PayloadChecksumKind::XAmzSha256 {
@@ -283,7 +288,7 @@ impl<'a> CanonicalRequest<'a> {
             }
 
             if params.settings().session_token_mode == SessionTokenMode::Exclude
-                && name == HeaderName::from_static(header::X_AMZ_SECURITY_TOKEN)
+                && name == HeaderName::from_static(token_header_name)
             {
                 continue;
             }
@@ -349,9 +354,13 @@ impl<'a> CanonicalRequest<'a> {
             );
 
             if let Some(security_token) = values.security_token {
-                if !settings.param_excluded(param::X_AMZ_SECURITY_TOKEN) {
-                    add_param(&mut params, param::X_AMZ_SECURITY_TOKEN, security_token);
-                }
+                add_param(
+                    &mut params,
+                    settings
+                        .session_token_name_override
+                        .unwrap_or(param::X_AMZ_SECURITY_TOKEN),
+                    security_token,
+                );
             }
         }
         // Sort by param name, and then by param value
diff --git a/aws/rust-runtime/aws-sigv4/src/http_request/settings.rs b/aws/rust-runtime/aws-sigv4/src/http_request/settings.rs
index b79f9909ac..9b51345866 100644
--- a/aws/rust-runtime/aws-sigv4/src/http_request/settings.rs
+++ b/aws/rust-runtime/aws-sigv4/src/http_request/settings.rs
@@ -30,9 +30,6 @@ pub struct SigningSettings {
     /// Headers that should be excluded from the signing process
     pub excluded_headers: Option<Vec<Cow<'static, str>>>,
 
-    /// Query params that should be excluded from the signing process
-    pub excluded_params: Option<Vec<Cow<'static, str>>>,
-
     /// Specifies whether the absolute path component of the URI should be normalized during signing.
     pub uri_path_normalization_mode: UriPathNormalizationMode,
 
@@ -40,22 +37,10 @@ pub struct SigningSettings {
     /// canonical request. Other services require only it to be added after
     /// calculating the signature.
     pub session_token_mode: SessionTokenMode,
-}
 
-impl SigningSettings {
-    pub(crate) fn header_excluded(&self, header: impl Into<Cow<'static, str>>) -> bool {
-        let header = header.into();
-        self.excluded_headers
-            .as_ref()
-            .is_some_and(|headers| headers.iter().any(|h| h == &header))
-    }
-
-    pub(crate) fn param_excluded(&self, param: impl Into<Cow<'static, str>>) -> bool {
-        let param = param.into();
-        self.excluded_params
-            .as_ref()
-            .is_some_and(|params| params.iter().any(|p| p == &param))
-    }
+    /// Some services require an alternative session token header or query param instead of
+    /// `x-amz-security-token` or `X-Amz-Security-Token`.
+    pub session_token_name_override: Option<&'static str>,
 }
 
 /// HTTP payload checksum type
@@ -150,9 +135,9 @@ impl Default for SigningSettings {
             signature_location: SignatureLocation::Headers,
             expires_in: None,
             excluded_headers,
-            excluded_params: None,
             uri_path_normalization_mode: UriPathNormalizationMode::Enabled,
             session_token_mode: SessionTokenMode::Include,
+            session_token_name_override: None,
         }
     }
 }
diff --git a/aws/rust-runtime/aws-sigv4/src/http_request/sign.rs b/aws/rust-runtime/aws-sigv4/src/http_request/sign.rs
index f7b6a4b664..dc8308dfda 100644
--- a/aws/rust-runtime/aws-sigv4/src/http_request/sign.rs
+++ b/aws/rust-runtime/aws-sigv4/src/http_request/sign.rs
@@ -296,15 +296,13 @@ fn calculate_signing_params<'a>(
     }
 
     if let Some(security_token) = creds.session_token() {
-        if !params
-            .settings()
-            .param_excluded(param::X_AMZ_SECURITY_TOKEN)
-        {
-            signing_params.push((
-                param::X_AMZ_SECURITY_TOKEN,
-                Cow::Owned(security_token.to_string()),
-            ));
-        }
+        signing_params.push((
+            params
+                .settings()
+                .session_token_name_override
+                .unwrap_or(param::X_AMZ_SECURITY_TOKEN),
+            Cow::Owned(security_token.to_string()),
+        ));
     }
 
     Ok((signing_params, signature))
@@ -371,17 +369,15 @@ fn calculate_signing_headers<'a>(
             }
 
             if let Some(security_token) = creds.session_token() {
-                if !params
-                    .settings
-                    .header_excluded(header::X_AMZ_SECURITY_TOKEN)
-                {
-                    add_header(
-                        &mut headers,
-                        header::X_AMZ_SECURITY_TOKEN,
-                        security_token,
-                        true,
-                    );
-                }
+                add_header(
+                    &mut headers,
+                    params
+                        .settings
+                        .session_token_name_override
+                        .unwrap_or(header::X_AMZ_SECURITY_TOKEN),
+                    security_token,
+                    true,
+                );
             }
             signature
         }

From 97cecd39d6e6c3c6185f6f486e1a9c96aedaa9ee Mon Sep 17 00:00:00 2001
From: ysaito1001 <awsaito@amazon.com>
Date: Thu, 15 Feb 2024 16:33:35 -0600
Subject: [PATCH 29/29] Add a tracking issue for `BuilderFromConfigBag`

This commit responds to https://github.com/smithy-lang/smithy-rs/pull/3388#discussion_r1486617970
---
 .../client/smithy/generators/config/ServiceConfigGenerator.kt  | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/ServiceConfigGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/ServiceConfigGenerator.kt
index 8bb9bcd039..40b89549b3 100644
--- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/ServiceConfigGenerator.kt
+++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/config/ServiceConfigGenerator.kt
@@ -80,6 +80,9 @@ sealed class ServiceConfig(name: String) : Section(name) {
     /** impl block of `ConfigBuilder` **/
     object BuilderImpl : ServiceConfig("BuilderImpl")
 
+    // It is important to ensure through type system that each field added to config implements this injection,
+    // tracked by smithy-rs#3419
+
     /**
      * Load a value from a config bag and store it in ConfigBuilder
      *  e.g.