diff --git a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpAuthDecoratorTest.kt b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpAuthDecoratorTest.kt index 76bb3f90b44..b07a3f825d5 100644 --- a/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpAuthDecoratorTest.kt +++ b/codegen-client/src/test/kotlin/software/amazon/smithy/rust/codegen/client/smithy/customizations/HttpAuthDecoratorTest.kt @@ -9,6 +9,7 @@ import org.junit.jupiter.api.Test import software.amazon.smithy.rust.codegen.client.testutil.clientIntegrationTest import software.amazon.smithy.rust.codegen.core.rustlang.Attribute import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency +import software.amazon.smithy.rust.codegen.core.rustlang.raw import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate import software.amazon.smithy.rust.codegen.core.smithy.RuntimeConfig import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType @@ -98,6 +99,139 @@ class HttpAuthDecoratorTest { } } + @Test + fun noAuthCustomAuth() { + clientIntegrationTest(TestModels.noSchemes) { ctx, rustCrate -> + rustCrate.integrationTest("custom_auth_scheme_works") { + val moduleName = ctx.moduleUseName() + raw( + """ + use aws_smithy_runtime_api::client::auth::static_resolver::StaticAuthSchemeOptionResolver; + use aws_smithy_runtime_api::client::auth::AuthScheme; + use aws_smithy_runtime_api::client::auth::{AuthSchemeId, Sign}; + use aws_smithy_runtime_api::client::identity::{ + IdentityFuture, ResolveIdentity, SharedIdentityResolver, + }; + use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents; + use aws_smithy_runtime_api::client::runtime_components::{ + GetIdentityResolver, RuntimeComponentsBuilder, + }; + use aws_smithy_runtime_api::client::runtime_plugin::RuntimePlugin; + use aws_smithy_types::config_bag::ConfigBag; + use std::borrow::Cow; + #[derive(Debug)] + struct CustomAuthRuntimePlugin { + components: RuntimeComponentsBuilder, + } + + impl RuntimePlugin for CustomAuthRuntimePlugin { + fn runtime_components( + &self, + _current_components: &RuntimeComponentsBuilder, + ) -> Cow<'_, RuntimeComponentsBuilder> { + Cow::Borrowed(&self.components) + } + } + + #[derive(Debug)] + struct TestAuthScheme; + + impl AuthScheme for TestAuthScheme { + fn scheme_id(&self) -> AuthSchemeId { + todo!() + } + + fn identity_resolver( + &self, + _identity_resolvers: &dyn GetIdentityResolver, + ) -> Option { + todo!() + } + + fn signer(&self) -> &dyn Sign { + todo!() + } + } + + #[derive(Debug)] + struct TestResolver; + impl ResolveIdentity for TestResolver { + fn resolve_identity<'a>( + &'a self, + _runtime_components: &'a RuntimeComponents, + _config_bag: &'a ConfigBag, + ) -> IdentityFuture<'a> { + todo!() + } + } + + impl CustomAuthRuntimePlugin { + pub fn new() -> Self { + let scheme_id = AuthSchemeId::new("basicauth"); + Self { + components: RuntimeComponentsBuilder::new("test-auth-scheme") + // Register our auth scheme + .with_auth_scheme(TestAuthScheme) + // Register our identity resolver with our auth scheme ID + .with_identity_resolver( + // This scheme ID needs to match the scheme ID returned in the auth scheme implementation + scheme_id, + TestResolver, + ) + // Set the auth scheme option resolver to always use our basic auth auth scheme + .with_auth_scheme_option_resolver(Some(StaticAuthSchemeOptionResolver::new(vec![ + scheme_id, + ]))), + } + } + } + + #[test] + fn compile() {} + + """, + + ) + Attribute.TokioTest.render(this) + rustTemplate( + """ + async fn apply_custom_auth_scheme() { + let (_guard, rx) = #{capture_test_logs}(); + let http_client = #{StaticReplayClient}::new( + vec![#{ReplayEvent}::new( + http::Request::builder() + .header("authorization", "Basic c29tZS11c2VyOnNvbWUtcGFzcw==") + .uri("http://localhost:1234/SomeOperation") + .body(#{SdkBody}::empty()) + .unwrap(), + http::Response::builder().status(200).body(#{SdkBody}::empty()).unwrap(), + )], + ); + let config = $moduleName::Config::builder() + .endpoint_url("http://localhost:1234") + .http_client(http_client.clone()) + .runtime_plugin(CustomAuthRuntimePlugin::new()) + .build(); + let client = $moduleName::Client::from_conf(config); + let req = client.some_operation() + .send() + .await; + + println!("{}", rx.contents()); + req.unwrap(); + panic!() + + + } + """, + "capture_test_logs" to CargoDependency.smithyRuntimeTestUtil(ctx.runtimeConfig).toType() + .resolve("test_util::capture_test_logs::capture_test_logs"), + *codegenScope(ctx.runtimeConfig), + ) + } + } + } + @Test fun apiKeyInQueryString() { clientIntegrationTest(TestModels.apiKeyInQueryString) { codegenContext, rustCrate -> @@ -329,6 +463,29 @@ private object TestModels { } """.asSmithyModel() + val noSchemes = """ + namespace test + + use aws.api#service + use aws.protocols#restJson1 + + @service(sdkId: "Test Api Key Auth") + @restJson1 + service TestService { + version: "2023-01-01", + operations: [SomeOperation] + } + + structure SomeOutput { + someAttribute: Long, + someVal: String + } + + @http(uri: "/SomeOperation", method: "GET") + operation SomeOperation { + output: SomeOutput + }""".asSmithyModel() + val apiKeyInQueryString = """ namespace test 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 6871f59f22e..e16b24d4bee 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 @@ -699,6 +699,9 @@ impl GetIdentityResolver for RuntimeComponents { #[cfg(all(test, feature = "test-util"))] mod tests { use super::{BuildError, RuntimeComponentsBuilder, Tracked}; + use crate::client::identity::{IdentityFuture, ResolveIdentity}; + use crate::client::runtime_components::RuntimeComponents; + use aws_smithy_types::config_bag::ConfigBag; #[test] #[allow(unreachable_pub)] @@ -829,4 +832,15 @@ mod tests { fn building_test_builder_should_not_panic() { let _ = RuntimeComponentsBuilder::for_tests().build(); // should not panic } + + struct TestResolver; + impl ResolveIdentity for TestResolver { + fn resolve_identity<'a>( + &'a self, + runtime_components: &'a RuntimeComponents, + config_bag: &'a ConfigBag, + ) -> IdentityFuture<'a> { + todo!() + } + } }