1use crate::{BoxedFuture, Context, MaybeSend, Result};
19use std::fmt::Debug;
20use std::future::Future;
21use std::ops::Deref;
22use std::time::Duration;
23
24pub trait SigningCredential: Clone + Debug + Send + Sync + Unpin + 'static {
26 fn is_valid(&self) -> bool;
28}
29
30impl<T: SigningCredential> SigningCredential for Option<T> {
31 fn is_valid(&self) -> bool {
32 let Some(ctx) = self else {
33 return false;
34 };
35
36 ctx.is_valid()
37 }
38}
39
40pub trait ProvideCredential: Debug + Send + Sync + Unpin + 'static {
45 type Credential: Send + Sync + Unpin + 'static;
49
50 fn provide_credential(
52 &self,
53 ctx: &Context,
54 ) -> impl Future<Output = Result<Option<Self::Credential>>> + MaybeSend;
55}
56
57pub trait ProvideCredentialDyn: Debug + Send + Sync + Unpin + 'static {
59 type Credential: Send + Sync + Unpin + 'static;
61
62 fn provide_credential_dyn<'a>(
64 &'a self,
65 ctx: &'a Context,
66 ) -> BoxedFuture<'a, Result<Option<Self::Credential>>>;
67}
68
69impl<T> ProvideCredentialDyn for T
70where
71 T: ProvideCredential + ?Sized,
72{
73 type Credential = T::Credential;
74
75 fn provide_credential_dyn<'a>(
76 &'a self,
77 ctx: &'a Context,
78 ) -> BoxedFuture<'a, Result<Option<Self::Credential>>> {
79 Box::pin(self.provide_credential(ctx))
80 }
81}
82
83impl<T> ProvideCredential for std::sync::Arc<T>
84where
85 T: ProvideCredentialDyn + ?Sized,
86{
87 type Credential = T::Credential;
88
89 async fn provide_credential(&self, ctx: &Context) -> Result<Option<Self::Credential>> {
90 self.deref().provide_credential_dyn(ctx).await
91 }
92}
93
94pub trait SignRequest: Debug + Send + Sync + Unpin + 'static {
96 type Credential: Send + Sync + Unpin + 'static;
100
101 fn sign_request<'a>(
115 &'a self,
116 ctx: &'a Context,
117 req: &'a mut http::request::Parts,
118 credential: Option<&'a Self::Credential>,
119 expires_in: Option<Duration>,
120 ) -> impl Future<Output = Result<()>> + MaybeSend + 'a;
121}
122
123pub trait SignRequestDyn: Debug + Send + Sync + Unpin + 'static {
125 type Credential: Send + Sync + Unpin + 'static;
127
128 fn sign_request_dyn<'a>(
130 &'a self,
131 ctx: &'a Context,
132 req: &'a mut http::request::Parts,
133 credential: Option<&'a Self::Credential>,
134 expires_in: Option<Duration>,
135 ) -> BoxedFuture<'a, Result<()>>;
136}
137
138impl<T> SignRequestDyn for T
139where
140 T: SignRequest + ?Sized,
141{
142 type Credential = T::Credential;
143
144 fn sign_request_dyn<'a>(
145 &'a self,
146 ctx: &'a Context,
147 req: &'a mut http::request::Parts,
148 credential: Option<&'a Self::Credential>,
149 expires_in: Option<Duration>,
150 ) -> BoxedFuture<'a, Result<()>> {
151 Box::pin(self.sign_request(ctx, req, credential, expires_in))
152 }
153}
154
155impl<T> SignRequest for std::sync::Arc<T>
156where
157 T: SignRequestDyn + ?Sized,
158{
159 type Credential = T::Credential;
160
161 async fn sign_request(
162 &self,
163 ctx: &Context,
164 req: &mut http::request::Parts,
165 credential: Option<&Self::Credential>,
166 expires_in: Option<Duration>,
167 ) -> Result<()> {
168 self.deref()
169 .sign_request_dyn(ctx, req, credential, expires_in)
170 .await
171 }
172}
173
174pub struct ProvideCredentialChain<C> {
210 providers: Vec<Box<dyn ProvideCredentialDyn<Credential = C>>>,
211}
212
213impl<C> ProvideCredentialChain<C>
214where
215 C: Send + Sync + Unpin + 'static,
216{
217 pub fn new() -> Self {
219 Self {
220 providers: Vec::new(),
221 }
222 }
223
224 pub fn push(mut self, provider: impl ProvideCredential<Credential = C> + 'static) -> Self {
226 self.providers.push(Box::new(provider));
227 self
228 }
229
230 pub fn push_front(
234 mut self,
235 provider: impl ProvideCredential<Credential = C> + 'static,
236 ) -> Self {
237 self.providers.insert(0, Box::new(provider));
238 self
239 }
240
241 pub fn from_vec(providers: Vec<Box<dyn ProvideCredentialDyn<Credential = C>>>) -> Self {
243 Self { providers }
244 }
245
246 pub fn len(&self) -> usize {
248 self.providers.len()
249 }
250
251 pub fn is_empty(&self) -> bool {
253 self.providers.is_empty()
254 }
255}
256
257impl<C> Default for ProvideCredentialChain<C>
258where
259 C: Send + Sync + Unpin + 'static,
260{
261 fn default() -> Self {
262 Self::new()
263 }
264}
265
266impl<C> Debug for ProvideCredentialChain<C>
267where
268 C: Send + Sync + Unpin + 'static,
269{
270 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
271 f.debug_struct("ProvideCredentialChain")
272 .field("providers_count", &self.providers.len())
273 .finish()
274 }
275}
276
277impl<C> ProvideCredential for ProvideCredentialChain<C>
278where
279 C: Send + Sync + Unpin + 'static,
280{
281 type Credential = C;
282
283 async fn provide_credential(&self, ctx: &Context) -> Result<Option<Self::Credential>> {
284 for provider in &self.providers {
285 log::debug!("Trying credential provider: {provider:?}");
286
287 match provider.provide_credential_dyn(ctx).await {
288 Ok(Some(cred)) => {
289 log::debug!("Successfully loaded credential from provider: {provider:?}");
290 return Ok(Some(cred));
291 }
292 Ok(None) => {
293 log::debug!("No credential found in provider: {provider:?}");
294 continue;
295 }
296 Err(e) => {
297 log::warn!("Error loading credential from provider {provider:?}: {e:?}");
298 continue;
300 }
301 }
302 }
303
304 Ok(None)
305 }
306}