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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .changelog/1763675274.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
applies_to:
- client
authors:
- ysaito1001
references:
- smithy-rs#4413
breaking: false
new_feature: false
bug_fix: true
---
Deprecate [NoAuthRuntimePlugin](https://docs.rs/aws-smithy-runtime/1.9.4/aws_smithy_runtime/client/auth/no_auth/struct.NoAuthRuntimePlugin.html), which does not properly configure the auth scheme option resolver for noAuth, and introduce `NoAuthRuntimePluginV2` that does.
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ private class AuthDecoratorConfigCustomizations(private val codegenContext: Clie
arrayOf(
*preludeScope,
"AuthScheme" to RuntimeType.smithyRuntimeApiClient(codegenContext.runtimeConfig).resolve("client::auth::AuthScheme"),
"NoAuthRuntimePluginV2" to
RuntimeType.smithyRuntime(codegenContext.runtimeConfig).resolve("client::auth::no_auth::NoAuthRuntimePluginV2"),
"ResolveAuthSchemeOptions" to AuthTypesGenerator(codegenContext).serviceSpecificResolveAuthSchemeTrait(),
"SharedAuthScheme" to RuntimeType.smithyRuntimeApiClient(codegenContext.runtimeConfig).resolve("client::auth::SharedAuthScheme"),
"SharedAuthSchemeOptionResolver" to RuntimeType.smithyRuntimeApiClient(codegenContext.runtimeConfig).resolve("client::auth::SharedAuthSchemeOptionResolver"),
Expand Down Expand Up @@ -281,6 +283,24 @@ private class AuthDecoratorConfigCustomizations(private val codegenContext: Clie
self.runtime_components.set_auth_scheme_option_resolver(#{Some}(auth_scheme_resolver.into_shared_resolver()));
self
}

/// Enable no authentication regardless of what authentication mechanisms operations support
///
/// This adds [NoAuthScheme](aws_smithy_runtime::client::auth::no_auth::NoAuthScheme) as a fallback
/// and the auth scheme resolver will use it when no other auth schemes are applicable.
pub fn allow_no_auth(mut self) -> Self {
self.set_allow_no_auth();
self
}

/// Enable no authentication regardless of what authentication mechanisms operations support
///
/// This adds [NoAuthScheme](aws_smithy_runtime::client::auth::no_auth::NoAuthScheme) as a fallback
/// and the auth scheme resolver will use it when no other auth schemes are applicable.
pub fn set_allow_no_auth(&mut self) -> &mut Self {
self.push_runtime_plugin(#{NoAuthRuntimePluginV2}::new().into_shared());
self
}
""",
*codegenScope,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package software.amazon.smithy.rust.codegen.client.smithy.auth

import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule
import software.amazon.smithy.rust.codegen.client.smithy.customizations.NoAuthSchemeOption
import software.amazon.smithy.rust.codegen.core.rustlang.join
import software.amazon.smithy.rust.codegen.core.rustlang.rust
import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate
Expand Down Expand Up @@ -208,32 +207,4 @@ class AuthSchemeResolverGenerator(
)
}
}

// TODO(https://github.com/smithy-lang/smithy-rs/issues/4177): Only used in protocol tests.
// Remove this once the issue has been addressed.
internal fun noAuthSchemeResolver(): RuntimeType {
return RuntimeType.forInlineFun("NoAuthSchemeResolver", ClientRustModule.Config.auth) {
rustTemplate(
"""
##[cfg(test)]
##[derive(Debug)]
pub(crate) struct NoAuthSchemeResolver;

##[cfg(test)]
impl ResolveAuthScheme for NoAuthSchemeResolver {
fn resolve_auth_scheme<'a>(
&'a self,
_params: &'a #{Params},
_cfg: &'a #{ConfigBag},
_runtime_components: &'a #{RuntimeComponents},
) -> #{AuthSchemeOptionsFuture}<'a> {
#{AuthSchemeOptionsFuture}::ready(#{Ok}(vec![#{NoAuthSchemeOption:W}]))
}
}
""",
*codegenScope,
"NoAuthSchemeOption" to NoAuthSchemeOption().render(codegenContext),
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ private fun baseClientRuntimePluginsFn(

let scope = ${codegenContext.moduleName.dq()};

##[allow(deprecated)]
let mut plugins = #{RuntimePlugins}::new()
// defaults
.with_client_plugins(#{default_plugins}(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

package software.amazon.smithy.rust.codegen.client.smithy.generators.protocol

import software.amazon.smithy.aws.traits.auth.SigV4Trait
import software.amazon.smithy.model.shapes.DoubleShape
import software.amazon.smithy.model.shapes.FloatShape
import software.amazon.smithy.model.shapes.OperationShape
Expand All @@ -16,7 +15,6 @@ import software.amazon.smithy.protocoltests.traits.HttpRequestTestCase
import software.amazon.smithy.protocoltests.traits.HttpResponseTestCase
import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext
import software.amazon.smithy.rust.codegen.client.smithy.ClientRustModule
import software.amazon.smithy.rust.codegen.client.smithy.auth.AuthSchemeResolverGenerator
import software.amazon.smithy.rust.codegen.client.smithy.generators.ClientInstantiator
import software.amazon.smithy.rust.codegen.core.rustlang.CargoDependency
import software.amazon.smithy.rust.codegen.core.rustlang.RustWriter
Expand Down Expand Up @@ -158,31 +156,16 @@ class ClientProtocolTestGenerator(
}
}
} ?: writable { }
// TODO(https://github.com/smithy-lang/smithy-rs/issues/4177):
// Until the incorrect separation is addressed, we need to rely on this workaround.
val noAuthSchemeResolver =
codegenContext.rootDecorator.authSchemeOptions(codegenContext, emptyList()).find {
it.authSchemeId == SigV4Trait.ID
}?.let { writable {} } ?: writable {
// If the `Sigv4AuthDecorator` is absent in the codegen plugin, we add `noAuth` as a fallback
// during protocol tests. This ensures compatibility when a test model references Sigv4,
// but the codegen, built with the generic client plugin, does not include the decorator.
rust(
".auth_scheme_resolver(#T)",
AuthSchemeResolverGenerator(
codegenContext,
emptyList(),
).noAuthSchemeResolver(),
)
}
// support test cases that set the host value, e.g: https://github.com/smithy-lang/smithy/blob/be68f3bbdfe5bf50a104b387094d40c8069f16b1/smithy-aws-protocol-tests/model/restJson1/endpoint-paths.smithy#L19
val host = "https://${httpRequestTestCase.host.orNull() ?: "example.com"}".dq()
rustTemplate(
"""
let (http_client, request_receiver) = #{capture_request}(None);
let config_builder = #{config}::Config::builder()
.with_test_defaults()
#{no_auth_scheme_resolver:W}
// TODO(https://github.com/smithy-lang/smithy-rs/issues/4177):
// Until the incorrect separation is addressed, we need to rely on this workaround.
.allow_no_auth()
.endpoint_url($host);
#{customParams}

Expand All @@ -192,7 +175,6 @@ class ClientProtocolTestGenerator(
.resolve("test_util::capture_request"),
"config" to ClientRustModule.config,
"customParams" to customParams,
"no_auth_scheme_resolver" to noAuthSchemeResolver,
)
renderClientCreation(this, ClientCreationParams(codegenContext, "http_client", "config_builder", "client"))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,45 @@ class AuthDecoratorTest {
""",
*codegenScope(codegenContext.runtimeConfig),
)

Attribute.TokioTest.render(this)
rustTemplate(
"""
async fn no_auth_aware_auth_scheme_option_resolver_via_plugin() {
let http_client = #{StaticReplayClient}::new(
vec![#{ReplayEvent}::new(
http::Request::builder()
.uri("http://localhost:1234/SomeOperation") // there shouldn't be `customidentitydata` in URI
.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())
.push_auth_scheme(CustomAuthScheme::default())
.auth_scheme_resolver(CustomAuthSchemeResolver)
// Configures a noAuth-aware auth scheme resolver that appends `NO_AUTH_SCHEME_ID`
// to the auth scheme options returned by `CustomAuthSchemeResolver`.
.runtime_plugin(#{NoAuthRuntimePluginV2}::new())
// Reorders resolved auth scheme options to place `NO_AUTH_SCHEME_ID` first.
.auth_scheme_preference([#{NO_AUTH_SCHEME_ID}])
.build();
let client = $moduleName::Client::from_conf(config);
let _ = client.some_operation().send().await.expect("success");
http_client.assert_requests_match(&[]);
}
""",
*codegenScope(codegenContext.runtimeConfig),
"NO_AUTH_SCHEME_ID" to
RuntimeType.smithyRuntime(codegenContext.runtimeConfig)
.resolve("client::auth::no_auth::NO_AUTH_SCHEME_ID"),
"NoAuthRuntimePluginV2" to
RuntimeType.smithyRuntime(codegenContext.runtimeConfig)
.resolve("client::auth::no_auth::NoAuthRuntimePluginV2"),
)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ allowLocalDeps=false
# Avoid registering dependencies/plugins/tasks that are only used for testing purposes
isTestingEnabled=true
# codegen publication version
codegenVersion=0.1.6
codegenVersion=0.1.7
2 changes: 1 addition & 1 deletion rust-runtime/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion rust-runtime/aws-smithy-runtime/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "aws-smithy-runtime"
version = "1.9.4"
version = "1.9.5"
authors = ["AWS Rust SDK Team <[email protected]>", "Zelda Hessler <[email protected]>"]
description = "The new smithy runtime crate"
edition = "2021"
Expand Down
100 changes: 99 additions & 1 deletion rust-runtime/aws-smithy-runtime/src/client/auth/no_auth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,19 @@

use crate::client::identity::no_auth::NoAuthIdentityResolver;
use aws_smithy_runtime_api::box_error::BoxError;
use aws_smithy_runtime_api::client::auth::static_resolver::StaticAuthSchemeOptionResolver;
use aws_smithy_runtime_api::client::auth::{
AuthScheme, AuthSchemeEndpointConfig, AuthSchemeId, SharedAuthScheme, Sign,
AuthScheme, AuthSchemeEndpointConfig, AuthSchemeId, AuthSchemeOption,
AuthSchemeOptionResolverParams, AuthSchemeOptionsFuture, ResolveAuthSchemeOptions,
SharedAuthScheme, SharedAuthSchemeOptionResolver, 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, RuntimeComponentsBuilder,
};
use aws_smithy_runtime_api::client::runtime_plugin::RuntimePlugin;
use aws_smithy_runtime_api::shared::IntoShared;
use aws_smithy_types::config_bag::ConfigBag;
use std::borrow::Cow;

Expand All @@ -26,16 +30,23 @@ pub const NO_AUTH_SCHEME_ID: AuthSchemeId = AuthSchemeId::new("noAuth");
///
/// This plugin can be used to disable authentication in certain cases, such as when there is
/// a Smithy `@optionalAuth` trait.
///
/// Note: This plugin does not work out of the box because it does not configure an auth scheme option resolver
/// that recognizes the `noAuth` scheme.
#[doc(hidden)]
#[non_exhaustive]
#[derive(Debug)]
#[deprecated(since = "1.9.5", note = "Use `NoAuthRuntimePluginV2` instead")]
pub struct NoAuthRuntimePlugin(RuntimeComponentsBuilder);

#[allow(deprecated)]
impl Default for NoAuthRuntimePlugin {
fn default() -> Self {
Self::new()
}
}

#[allow(deprecated)]
impl NoAuthRuntimePlugin {
/// Creates a new `NoAuthRuntimePlugin`.
pub fn new() -> Self {
Expand All @@ -50,6 +61,7 @@ impl NoAuthRuntimePlugin {
}
}

#[allow(deprecated)]
impl RuntimePlugin for NoAuthRuntimePlugin {
fn runtime_components(
&self,
Expand All @@ -59,6 +71,92 @@ impl RuntimePlugin for NoAuthRuntimePlugin {
}
}

/// A [`RuntimePlugin`] that registers a "no auth" identity resolver, auth scheme, and auth scheme option resolver.
///
/// Ideally, a Smithy model should use `@optionalAuth` or `@auth([])` on operations so that:
/// - The Smithy runtime supports the no-auth scheme
/// - The code-generated default auth scheme option resolver includes the no-auth scheme for those operations
///
/// When that is not possible, this plugin can be used to achieve the same effect.
#[derive(Debug)]
pub struct NoAuthRuntimePluginV2(RuntimeComponentsBuilder);

impl Default for NoAuthRuntimePluginV2 {
fn default() -> Self {
Self::new()
}
}

impl NoAuthRuntimePluginV2 {
/// Creates a new `NoAuthRuntimePluginV2`.
pub fn new() -> Self {
Self(
RuntimeComponentsBuilder::new("NoAuthRuntimePluginV2")
.with_identity_resolver(
NO_AUTH_SCHEME_ID,
SharedIdentityResolver::new(NoAuthIdentityResolver::new()),
)
.with_auth_scheme(SharedAuthScheme::new(NoAuthScheme::new())),
)
}
}

impl RuntimePlugin for NoAuthRuntimePluginV2 {
fn runtime_components(
&self,
current_components: &RuntimeComponentsBuilder,
) -> Cow<'_, RuntimeComponentsBuilder> {
// No auth scheme option resolver is configured here because it needs to access
// the existing resolver (likely the code-generated default) stored in the
// current runtime components builder.
let auth_scheme_option_resolver: SharedAuthSchemeOptionResolver =
match current_components.auth_scheme_option_resolver() {
Some(current_resolver) => {
NoAuthSchemeOptionResolver::new(current_resolver.clone()).into_shared()
}
None => StaticAuthSchemeOptionResolver::new(vec![NO_AUTH_SCHEME_ID]).into_shared(),
};
Cow::Owned(
self.0
.clone()
.with_auth_scheme_option_resolver(Some(auth_scheme_option_resolver)),
)
}
}

#[derive(Debug)]
struct NoAuthSchemeOptionResolver<R> {
inner: R,
}

impl<R> NoAuthSchemeOptionResolver<R> {
fn new(inner: R) -> Self {
Self { inner }
}
}

impl<R> ResolveAuthSchemeOptions for NoAuthSchemeOptionResolver<R>
where
R: ResolveAuthSchemeOptions,
{
fn resolve_auth_scheme_options_v2<'a>(
&'a self,
params: &'a AuthSchemeOptionResolverParams,
cfg: &'a ConfigBag,
runtime_components: &'a RuntimeComponents,
) -> AuthSchemeOptionsFuture<'a> {
let inner_future =
self.inner
.resolve_auth_scheme_options_v2(params, cfg, runtime_components);

AuthSchemeOptionsFuture::new(async move {
let mut options = inner_future.await?;
options.push(AuthSchemeOption::from(NO_AUTH_SCHEME_ID));
Ok(options)
})
}
}

/// The "no auth" auth scheme.
///
/// The orchestrator requires an auth scheme, so Smithy's `@optionalAuth` trait is implemented
Expand Down
Loading
Loading