aws_credential_types/provider/
credentials.rs1#![cfg_attr(
20    feature = "hardcoded-credentials",
21    doc = r##"
22See [`Credentials::from_keys`] for an example on how to use static credentials.
23    "##
24)]
25#![cfg_attr(
26    not(feature = "hardcoded-credentials"),
27    doc = r##"
28Enable the `hardcoded-credentials` feature to be able to use `Credentials::from_keys` to
29construct credentials from hardcoded values.
30    "##
31)]
32
33use crate::Credentials;
75use aws_smithy_runtime_api::client::identity::{
76    Identity, IdentityCachePartition, IdentityFuture, ResolveIdentity,
77};
78use aws_smithy_runtime_api::client::runtime_components::RuntimeComponents;
79use aws_smithy_types::config_bag::{ConfigBag, Storable, StoreReplace};
80use std::sync::Arc;
81
82pub type Result = std::result::Result<Credentials, super::error::CredentialsError>;
84
85pub trait ProvideCredentials: Send + Sync + std::fmt::Debug {
87    fn provide_credentials<'a>(&'a self) -> super::future::ProvideCredentials<'a>
89    where
90        Self: 'a;
91
92    fn fallback_on_interrupt(&self) -> Option<Credentials> {
102        None
103    }
104}
105
106impl ProvideCredentials for Credentials {
107    fn provide_credentials<'a>(&'a self) -> super::future::ProvideCredentials<'a>
108    where
109        Self: 'a,
110    {
111        super::future::ProvideCredentials::ready(Ok(self.clone()))
112    }
113}
114
115impl ProvideCredentials for Arc<dyn ProvideCredentials> {
116    fn provide_credentials<'a>(&'a self) -> super::future::ProvideCredentials<'a>
117    where
118        Self: 'a,
119    {
120        self.as_ref().provide_credentials()
121    }
122}
123
124#[derive(Clone, Debug)]
129pub struct SharedCredentialsProvider(Arc<dyn ProvideCredentials>, IdentityCachePartition);
130
131impl SharedCredentialsProvider {
132    pub fn new(provider: impl ProvideCredentials + 'static) -> Self {
137        Self(Arc::new(provider), IdentityCachePartition::new())
138    }
139}
140
141impl AsRef<dyn ProvideCredentials> for SharedCredentialsProvider {
142    fn as_ref(&self) -> &(dyn ProvideCredentials + 'static) {
143        self.0.as_ref()
144    }
145}
146
147impl From<Arc<dyn ProvideCredentials>> for SharedCredentialsProvider {
148    fn from(provider: Arc<dyn ProvideCredentials>) -> Self {
149        SharedCredentialsProvider(provider, IdentityCachePartition::new())
150    }
151}
152
153impl ProvideCredentials for SharedCredentialsProvider {
154    fn provide_credentials<'a>(&'a self) -> super::future::ProvideCredentials<'a>
155    where
156        Self: 'a,
157    {
158        self.0.provide_credentials()
159    }
160}
161
162impl Storable for SharedCredentialsProvider {
163    type Storer = StoreReplace<SharedCredentialsProvider>;
164}
165
166impl ResolveIdentity for SharedCredentialsProvider {
167    fn resolve_identity<'a>(
168        &'a self,
169        _runtime_components: &'a RuntimeComponents,
170        _config_bag: &'a ConfigBag,
171    ) -> IdentityFuture<'a> {
172        IdentityFuture::new(async move { Ok(self.provide_credentials().await?.into()) })
173    }
174
175    fn fallback_on_interrupt(&self) -> Option<Identity> {
176        ProvideCredentials::fallback_on_interrupt(self).map(|creds| creds.into())
177    }
178
179    fn cache_partition(&self) -> Option<IdentityCachePartition> {
180        Some(self.1)
181    }
182}
183
184#[cfg(test)]
185mod tests {
186    use aws_smithy_runtime_api::client::{
187        identity::SharedIdentityResolver, runtime_components::RuntimeComponentsBuilder,
188    };
189
190    use crate::attributes::AccountId;
191
192    use super::*;
193
194    #[test]
195    fn reuses_cache_partition() {
196        let creds = Credentials::new("AKID", "SECRET", None, None, "test");
197        let provider = SharedCredentialsProvider::new(creds);
198        let partition = provider.cache_partition();
199        assert!(partition.is_some());
200
201        let identity_resolver = SharedIdentityResolver::new(provider);
202        let identity_partition = identity_resolver.cache_partition();
203
204        assert!(partition.unwrap() == identity_partition);
205    }
206
207    #[tokio::test]
208    async fn account_id_can_be_retrieved_from_identity() {
209        let expected_account_id = "012345678901";
210        let creds = Credentials::builder()
211            .access_key_id("AKID")
212            .secret_access_key("SECRET")
213            .account_id(expected_account_id)
214            .provider_name("test")
215            .build();
216        let provider = SharedCredentialsProvider::new(creds);
217        let identity = provider
218            .resolve_identity(
219                &RuntimeComponentsBuilder::for_tests().build().unwrap(),
220                &ConfigBag::base(),
221            )
222            .await
223            .unwrap();
224        let actual = identity.property::<AccountId>().unwrap();
225        assert_eq!(expected_account_id, actual.as_str());
226    }
227}