aws_config/environment/
credentials.rs1use std::env::VarError;
7
8use aws_credential_types::attributes::AccountId;
9use aws_credential_types::provider::{self, error::CredentialsError, future, ProvideCredentials};
10use aws_credential_types::Credentials;
11use aws_types::os_shim_internal::Env;
12
13#[derive(Debug, Clone)]
21pub struct EnvironmentVariableCredentialsProvider {
22 env: Env,
23}
24
25impl EnvironmentVariableCredentialsProvider {
26 fn credentials(&self) -> provider::Result {
27 let access_key = self
28 .env
29 .get("AWS_ACCESS_KEY_ID")
30 .and_then(err_if_blank)
31 .map_err(to_cred_error)?;
32 let secret_key = self
33 .env
34 .get("AWS_SECRET_ACCESS_KEY")
35 .and_then(err_if_blank)
36 .or_else(|_| self.env.get("SECRET_ACCESS_KEY"))
37 .and_then(err_if_blank)
38 .map_err(to_cred_error)?;
39 let session_token =
40 self.env
41 .get("AWS_SESSION_TOKEN")
42 .ok()
43 .and_then(|token| match token.trim() {
44 "" => None,
45 s => Some(s.to_string()),
46 });
47 let account_id =
48 self.env
49 .get("AWS_ACCOUNT_ID")
50 .ok()
51 .and_then(|account_id| match account_id.trim() {
52 "" => None,
53 s => Some(AccountId::from(s)),
54 });
55 let mut builder = Credentials::builder()
56 .access_key_id(access_key)
57 .secret_access_key(secret_key)
58 .provider_name(ENV_PROVIDER);
59 builder.set_session_token(session_token);
60 builder.set_account_id(account_id);
61 Ok(builder.build())
62 }
63}
64
65impl EnvironmentVariableCredentialsProvider {
66 pub fn new() -> Self {
68 Self::new_with_env(Env::real())
69 }
70
71 pub(crate) fn new_with_env(env: Env) -> Self {
75 Self { env }
76 }
77}
78
79impl Default for EnvironmentVariableCredentialsProvider {
80 fn default() -> Self {
81 Self::new()
82 }
83}
84
85const ENV_PROVIDER: &str = "EnvironmentVariable";
86
87impl ProvideCredentials for EnvironmentVariableCredentialsProvider {
88 fn provide_credentials<'a>(&'a self) -> future::ProvideCredentials<'a>
89 where
90 Self: 'a,
91 {
92 future::ProvideCredentials::ready(self.credentials())
93 }
94}
95
96fn to_cred_error(err: VarError) -> CredentialsError {
97 match err {
98 VarError::NotPresent => CredentialsError::not_loaded("environment variable not set"),
99 e @ VarError::NotUnicode(_) => CredentialsError::unhandled(e),
100 }
101}
102
103fn err_if_blank(value: String) -> Result<String, VarError> {
104 if value.trim().is_empty() {
105 Err(VarError::NotPresent)
106 } else {
107 Ok(value)
108 }
109}
110
111#[cfg(test)]
112mod test {
113 use aws_credential_types::provider::{error::CredentialsError, ProvideCredentials};
114 use aws_types::os_shim_internal::Env;
115 use futures_util::FutureExt;
116
117 use super::EnvironmentVariableCredentialsProvider;
118
119 fn make_provider(vars: &[(&str, &str)]) -> EnvironmentVariableCredentialsProvider {
120 EnvironmentVariableCredentialsProvider {
121 env: Env::from_slice(vars),
122 }
123 }
124
125 #[test]
126 fn valid_no_token() {
127 let provider = make_provider(&[
128 ("AWS_ACCESS_KEY_ID", "access"),
129 ("AWS_SECRET_ACCESS_KEY", "secret"),
130 ]);
131 let creds = provider
132 .provide_credentials()
133 .now_or_never()
134 .unwrap()
135 .expect("valid credentials");
136 assert_eq!(creds.session_token(), None);
137 assert_eq!(creds.access_key_id(), "access");
138 assert_eq!(creds.secret_access_key(), "secret");
139 }
140
141 #[test]
142 fn valid_with_token() {
143 let provider = make_provider(&[
144 ("AWS_ACCESS_KEY_ID", "access"),
145 ("AWS_SECRET_ACCESS_KEY", "secret"),
146 ("AWS_SESSION_TOKEN", "token"),
147 ]);
148
149 let creds = provider
150 .provide_credentials()
151 .now_or_never()
152 .unwrap()
153 .expect("valid credentials");
154 assert_eq!(creds.session_token().unwrap(), "token");
155 assert_eq!(creds.access_key_id(), "access");
156 assert_eq!(creds.secret_access_key(), "secret");
157 }
158
159 #[test]
160 fn empty_token_env_var() {
161 for token_value in &["", " "] {
162 let provider = make_provider(&[
163 ("AWS_ACCESS_KEY_ID", "access"),
164 ("AWS_SECRET_ACCESS_KEY", "secret"),
165 ("AWS_SESSION_TOKEN", token_value),
166 ]);
167
168 let creds = provider
169 .provide_credentials()
170 .now_or_never()
171 .unwrap()
172 .expect("valid credentials");
173 assert_eq!(creds.access_key_id(), "access");
174 assert_eq!(creds.secret_access_key(), "secret");
175 assert_eq!(creds.session_token(), None);
176 }
177 }
178
179 #[test]
180 fn secret_key_fallback() {
181 let provider = make_provider(&[
182 ("AWS_ACCESS_KEY_ID", "access"),
183 ("SECRET_ACCESS_KEY", "secret"),
184 ("AWS_SESSION_TOKEN", "token"),
185 ]);
186
187 let creds = provider
188 .provide_credentials()
189 .now_or_never()
190 .unwrap()
191 .expect("valid credentials");
192 assert_eq!(creds.session_token().unwrap(), "token");
193 assert_eq!(creds.access_key_id(), "access");
194 assert_eq!(creds.secret_access_key(), "secret");
195 }
196
197 #[test]
198 fn secret_key_fallback_empty() {
199 let provider = make_provider(&[
200 ("AWS_ACCESS_KEY_ID", "access"),
201 ("AWS_SECRET_ACCESS_KEY", " "),
202 ("SECRET_ACCESS_KEY", "secret"),
203 ("AWS_SESSION_TOKEN", "token"),
204 ]);
205
206 let creds = provider
207 .provide_credentials()
208 .now_or_never()
209 .unwrap()
210 .expect("valid credentials");
211 assert_eq!(creds.session_token().unwrap(), "token");
212 assert_eq!(creds.access_key_id(), "access");
213 assert_eq!(creds.secret_access_key(), "secret");
214 }
215
216 #[test]
217 fn missing() {
218 let provider = make_provider(&[]);
219 let err = provider
220 .provide_credentials()
221 .now_or_never()
222 .unwrap()
223 .expect_err("no credentials defined");
224 assert!(matches!(err, CredentialsError::CredentialsNotLoaded { .. }));
225 }
226
227 #[test]
228 fn empty_keys_env_vars() {
229 for [access_key_value, secret_key_value] in &[
230 &["", ""],
231 &[" ", ""],
232 &["access", ""],
233 &["", " "],
234 &[" ", " "],
235 &["access", " "],
236 &["", "secret"],
237 &[" ", "secret"],
238 ] {
239 let provider = make_provider(&[
240 ("AWS_ACCESS_KEY_ID", access_key_value),
241 ("AWS_SECRET_ACCESS_KEY", secret_key_value),
242 ]);
243
244 let err = provider
245 .provide_credentials()
246 .now_or_never()
247 .unwrap()
248 .expect_err("no credentials defined");
249 assert!(matches!(err, CredentialsError::CredentialsNotLoaded { .. }));
250 }
251 }
252
253 #[test]
254 fn real_environment() {
255 let provider = EnvironmentVariableCredentialsProvider::new();
256 let _fut = provider.provide_credentials();
258 }
259}