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(AuthSchemeId::from(Cow::Owned(scheme_name.to_owned())))
57 })
58 .collect::<Result<Vec<_>, _>>()
59 .map(AuthSchemePreference::from)
60}
61
62#[derive(Debug)]
63pub(crate) struct InvalidAuthSchemeNamesCsv {
64 value: String,
65}
66
67impl fmt::Display for InvalidAuthSchemeNamesCsv {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 write!(
70 f,
71 "Not a valid comma-separated auth scheme names: {}",
72 self.value
73 )
74 }
75}
76
77impl std::error::Error for InvalidAuthSchemeNamesCsv {}
78
79#[cfg(test)]
80mod test {
81 use super::env;
82 use crate::{
83 default_provider::auth_scheme_preference::auth_scheme_preference_provider,
84 provider_config::ProviderConfig,
85 };
86 use aws_types::os_shim_internal::Env;
87 use tracing_test::traced_test;
88
89 #[tokio::test]
90 #[traced_test]
91 async fn log_error_on_invalid_value() {
92 let conf = ProviderConfig::empty().with_env(Env::from_slice(&[(
93 env::AUTH_SCHEME_PREFERENCE,
94 "scheme1, , \tscheme2",
95 )]));
96 assert_eq!(None, auth_scheme_preference_provider(&conf).await);
97 assert!(logs_contain(
98 "Not a valid comma-separated auth scheme names: Empty name found"
99 ));
100 }
101
102 #[cfg(feature = "sso")] mod http_auth_tests {
104 use super::env;
105 #[allow(deprecated)]
106 use crate::profile::profile_file::{ProfileFileKind, ProfileFiles};
107 use crate::{
108 default_provider::auth_scheme_preference::auth_scheme_preference_provider,
109 provider_config::ProviderConfig,
110 };
111 use aws_smithy_runtime_api::client::auth::AuthSchemePreference;
112 use aws_types::os_shim_internal::{Env, Fs};
113
114 #[tokio::test]
115 async fn environment_priority() {
116 let conf = ProviderConfig::empty()
117 .with_env(Env::from_slice(&[(
118 env::AUTH_SCHEME_PREFERENCE,
119 "aws.auth#sigv4, smithy.api#httpBasicAuth, smithy.api#httpDigestAuth, smithy.api#httpBearerAuth, smithy.api#httpApiKeyAuth",
120 )]))
121 .with_profile_config(
122 Some(
123 #[allow(deprecated)]
124 ProfileFiles::builder()
125 .with_file(
126 #[allow(deprecated)]
127 ProfileFileKind::Config,
128 "conf",
129 )
130 .build(),
131 ),
132 None,
133 )
134 .with_fs(Fs::from_slice(&[(
135 "conf",
136 "[default]\nauth_scheme_preference = scheme1, scheme2 , \tscheme3 \t",
137 )]));
138 assert_eq!(
139 AuthSchemePreference::from([
140 aws_runtime::auth::sigv4::SCHEME_ID,
141 aws_smithy_runtime_api::client::auth::http::HTTP_BASIC_AUTH_SCHEME_ID,
142 aws_smithy_runtime_api::client::auth::http::HTTP_DIGEST_AUTH_SCHEME_ID,
143 aws_smithy_runtime_api::client::auth::http::HTTP_BEARER_AUTH_SCHEME_ID,
144 aws_smithy_runtime_api::client::auth::http::HTTP_API_KEY_AUTH_SCHEME_ID,
145 ]),
146 auth_scheme_preference_provider(&conf).await.unwrap()
147 );
148 }
149
150 #[tokio::test]
151 async fn load_from_profile() {
152 let conf = ProviderConfig::empty()
153 .with_profile_config(
154 Some(
155 #[allow(deprecated)]
156 ProfileFiles::builder()
157 .with_file(
158 #[allow(deprecated)]
159 ProfileFileKind::Config,
160 "conf",
161 )
162 .build(),
163 ),
164 None,
165 )
166 .with_fs(Fs::from_slice(&[(
167 "conf",
168 "[default]\nauth_scheme_preference = sigv4, httpBasicAuth, httpDigestAuth, \thttpBearerAuth \t, httpApiKeyAuth ",
169 )]));
170 assert_eq!(
171 AuthSchemePreference::from([
172 aws_runtime::auth::sigv4::SCHEME_ID,
173 aws_smithy_runtime_api::client::auth::http::HTTP_BASIC_AUTH_SCHEME_ID,
174 aws_smithy_runtime_api::client::auth::http::HTTP_DIGEST_AUTH_SCHEME_ID,
175 aws_smithy_runtime_api::client::auth::http::HTTP_BEARER_AUTH_SCHEME_ID,
176 aws_smithy_runtime_api::client::auth::http::HTTP_API_KEY_AUTH_SCHEME_ID,
177 ]),
178 auth_scheme_preference_provider(&conf).await.unwrap()
179 );
180 }
181 }
182}