aws_config/default_provider/
auth_scheme_preference.rs1use crate::provider_config::ProviderConfig;
7use aws_runtime::env_config::EnvConfigValue;
8use aws_smithy_runtime_api::client::auth::{AuthSchemeId, AuthSchemePreference};
9use aws_smithy_types::error::display::DisplayErrorContext;
10use std::borrow::Cow;
11use std::fmt;
12
13mod env {
14 pub(super) const AUTH_SCHEME_PREFERENCE: &str = "AWS_AUTH_SCHEME_PREFERENCE";
15}
16
17mod profile_key {
18 pub(super) const AUTH_SCHEME_PREFERENCE: &str = "auth_scheme_preference";
19}
20
21pub(crate) async fn auth_scheme_preference_provider(
33 provider_config: &ProviderConfig,
34) -> Option<AuthSchemePreference> {
35 let env = provider_config.env();
36 let profiles = provider_config.profile().await;
37
38 EnvConfigValue::new()
39 .env(env::AUTH_SCHEME_PREFERENCE)
40 .profile(profile_key::AUTH_SCHEME_PREFERENCE)
41 .validate(&env, profiles, parse_auth_scheme_names)
42 .map_err(|err| tracing::warn!(err = %DisplayErrorContext(&err), "invalid value for `AuthSchemePreference`"))
43 .unwrap_or(None)
44}
45
46fn parse_auth_scheme_names(csv: &str) -> Result<AuthSchemePreference, InvalidAuthSchemeNamesCsv> {
47 csv.split(',')
48 .map(|s| {
49 let trimmed = s.trim().replace([' ', '\t'], "");
50 if trimmed.is_empty() {
51 return Err(InvalidAuthSchemeNamesCsv {
52 value: format!("Empty name found in `{csv}`."),
53 });
54 }
55 let scheme_name = trimmed.split('#').next_back().unwrap_or(&trimmed);
56 Ok(runtime_api_auth_scheme_id(scheme_name))
57 })
58 .collect::<Result<Vec<_>, _>>()
59 .map(AuthSchemePreference::from)
60}
61
62fn runtime_api_auth_scheme_id(auth_scheme_name: &str) -> AuthSchemeId {
70 let runtime_api_auth_scheme_str = match auth_scheme_name {
71 "httpBasicAuth" => "http-basic-auth",
72 "httpDigestAuth" => "http-digest-auth",
73 "httpBearerAuth" => "http-bearer-auth",
74 "httpApiKeyAuth" => "http-api-key-auth",
75 "noAuth" => "no_auth",
76 otherwise => otherwise,
77 };
78 AuthSchemeId::from(Cow::Owned(runtime_api_auth_scheme_str.to_owned()))
79}
80
81#[derive(Debug)]
82pub(crate) struct InvalidAuthSchemeNamesCsv {
83 value: String,
84}
85
86impl fmt::Display for InvalidAuthSchemeNamesCsv {
87 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
88 write!(
89 f,
90 "Not a valid comma-separated auth scheme names: {}",
91 self.value
92 )
93 }
94}
95
96impl std::error::Error for InvalidAuthSchemeNamesCsv {}
97
98#[cfg(test)]
99mod test {
100 use super::env;
101 use crate::{
102 default_provider::auth_scheme_preference::auth_scheme_preference_provider,
103 provider_config::ProviderConfig,
104 };
105 use aws_types::os_shim_internal::Env;
106 use tracing_test::traced_test;
107
108 #[tokio::test]
109 #[traced_test]
110 async fn log_error_on_invalid_value() {
111 let conf = ProviderConfig::empty().with_env(Env::from_slice(&[(
112 env::AUTH_SCHEME_PREFERENCE,
113 "scheme1, , \tscheme2",
114 )]));
115 assert_eq!(None, auth_scheme_preference_provider(&conf).await);
116 assert!(logs_contain(
117 "Not a valid comma-separated auth scheme names: Empty name found"
118 ));
119 }
120
121 #[cfg(feature = "sso")] mod http_auth_tests {
123 use super::env;
124 #[allow(deprecated)]
125 use crate::profile::profile_file::{ProfileFileKind, ProfileFiles};
126 use crate::{
127 default_provider::auth_scheme_preference::auth_scheme_preference_provider,
128 provider_config::ProviderConfig,
129 };
130 use aws_smithy_runtime_api::client::auth::AuthSchemePreference;
131 use aws_types::os_shim_internal::{Env, Fs};
132
133 #[tokio::test]
134 async fn environment_priority() {
135 let conf = ProviderConfig::empty()
136 .with_env(Env::from_slice(&[(
137 env::AUTH_SCHEME_PREFERENCE,
138 "aws.auth#sigv4, smithy.api#httpBasicAuth, smithy.api#httpDigestAuth, smithy.api#httpBearerAuth, smithy.api#httpApiKeyAuth",
139 )]))
140 .with_profile_config(
141 Some(
142 #[allow(deprecated)]
143 ProfileFiles::builder()
144 .with_file(
145 #[allow(deprecated)]
146 ProfileFileKind::Config,
147 "conf",
148 )
149 .build(),
150 ),
151 None,
152 )
153 .with_fs(Fs::from_slice(&[(
154 "conf",
155 "[default]\nauth_scheme_preference = scheme1, scheme2 , \tscheme3 \t",
156 )]));
157 assert_eq!(
158 AuthSchemePreference::from([
159 aws_runtime::auth::sigv4::SCHEME_ID,
160 aws_smithy_runtime_api::client::auth::http::HTTP_BASIC_AUTH_SCHEME_ID,
161 aws_smithy_runtime_api::client::auth::http::HTTP_DIGEST_AUTH_SCHEME_ID,
162 aws_smithy_runtime_api::client::auth::http::HTTP_BEARER_AUTH_SCHEME_ID,
163 aws_smithy_runtime_api::client::auth::http::HTTP_API_KEY_AUTH_SCHEME_ID,
164 ]),
165 auth_scheme_preference_provider(&conf).await.unwrap()
166 );
167 }
168
169 #[tokio::test]
170 async fn load_from_profile() {
171 let conf = ProviderConfig::empty()
172 .with_profile_config(
173 Some(
174 #[allow(deprecated)]
175 ProfileFiles::builder()
176 .with_file(
177 #[allow(deprecated)]
178 ProfileFileKind::Config,
179 "conf",
180 )
181 .build(),
182 ),
183 None,
184 )
185 .with_fs(Fs::from_slice(&[(
186 "conf",
187 "[default]\nauth_scheme_preference = sigv4, httpBasicAuth, httpDigestAuth, \thttpBearerAuth \t, httpApiKeyAuth ",
188 )]));
189 assert_eq!(
190 AuthSchemePreference::from([
191 aws_runtime::auth::sigv4::SCHEME_ID,
192 aws_smithy_runtime_api::client::auth::http::HTTP_BASIC_AUTH_SCHEME_ID,
193 aws_smithy_runtime_api::client::auth::http::HTTP_DIGEST_AUTH_SCHEME_ID,
194 aws_smithy_runtime_api::client::auth::http::HTTP_BEARER_AUTH_SCHEME_ID,
195 aws_smithy_runtime_api::client::auth::http::HTTP_API_KEY_AUTH_SCHEME_ID,
196 ]),
197 auth_scheme_preference_provider(&conf).await.unwrap()
198 );
199 }
200 }
201}