1use crate::time::Timestamp;
19use crate::{BoxedFuture, Context, MaybeSend, Result};
20use std::fmt::Debug;
21use std::future::Future;
22use std::ops::Deref;
23use std::time::Duration;
24
25pub trait SigningCredential: Clone + Debug + Send + Sync + Unpin + 'static {
27 fn is_valid(&self) -> bool;
32
33 fn is_valid_at(&self, _ts: Timestamp) -> bool {
35 self.is_valid()
36 }
37}
38
39impl<T: SigningCredential> SigningCredential for Option<T> {
40 fn is_valid(&self) -> bool {
41 let Some(ctx) = self else {
42 return false;
43 };
44
45 ctx.is_valid()
46 }
47}
48
49pub trait ProvideCredential: Debug + Send + Sync + Unpin + 'static {
54 type Credential: Send + Sync + Unpin + 'static;
58
59 fn provide_credential(
61 &self,
62 ctx: &Context,
63 ) -> impl Future<Output = Result<Option<Self::Credential>>> + MaybeSend;
64}
65
66pub trait ProvideCredentialDyn: Debug + Send + Sync + Unpin + 'static {
68 type Credential: Send + Sync + Unpin + 'static;
70
71 fn provide_credential_dyn<'a>(
73 &'a self,
74 ctx: &'a Context,
75 ) -> BoxedFuture<'a, Result<Option<Self::Credential>>>;
76}
77
78impl<T> ProvideCredentialDyn for T
79where
80 T: ProvideCredential + ?Sized,
81{
82 type Credential = T::Credential;
83
84 fn provide_credential_dyn<'a>(
85 &'a self,
86 ctx: &'a Context,
87 ) -> BoxedFuture<'a, Result<Option<Self::Credential>>> {
88 Box::pin(self.provide_credential(ctx))
89 }
90}
91
92impl<T> ProvideCredential for std::sync::Arc<T>
93where
94 T: ProvideCredentialDyn + ?Sized,
95{
96 type Credential = T::Credential;
97
98 async fn provide_credential(&self, ctx: &Context) -> Result<Option<Self::Credential>> {
99 self.deref().provide_credential_dyn(ctx).await
100 }
101}
102
103pub trait SignRequest: Debug + Send + Sync + Unpin + 'static {
105 type Credential: Send + Sync + Unpin + 'static;
109
110 fn sign_request<'a>(
124 &'a self,
125 ctx: &'a Context,
126 req: &'a mut http::request::Parts,
127 credential: Option<&'a Self::Credential>,
128 expires_in: Option<Duration>,
129 ) -> impl Future<Output = Result<()>> + MaybeSend + 'a;
130}
131
132pub trait SignRequestDyn: Debug + Send + Sync + Unpin + 'static {
134 type Credential: Send + Sync + Unpin + 'static;
136
137 fn sign_request_dyn<'a>(
139 &'a self,
140 ctx: &'a Context,
141 req: &'a mut http::request::Parts,
142 credential: Option<&'a Self::Credential>,
143 expires_in: Option<Duration>,
144 ) -> BoxedFuture<'a, Result<()>>;
145}
146
147impl<T> SignRequestDyn for T
148where
149 T: SignRequest + ?Sized,
150{
151 type Credential = T::Credential;
152
153 fn sign_request_dyn<'a>(
154 &'a self,
155 ctx: &'a Context,
156 req: &'a mut http::request::Parts,
157 credential: Option<&'a Self::Credential>,
158 expires_in: Option<Duration>,
159 ) -> BoxedFuture<'a, Result<()>> {
160 Box::pin(self.sign_request(ctx, req, credential, expires_in))
161 }
162}
163
164impl<T> SignRequest for std::sync::Arc<T>
165where
166 T: SignRequestDyn + ?Sized,
167{
168 type Credential = T::Credential;
169
170 async fn sign_request(
171 &self,
172 ctx: &Context,
173 req: &mut http::request::Parts,
174 credential: Option<&Self::Credential>,
175 expires_in: Option<Duration>,
176 ) -> Result<()> {
177 self.deref()
178 .sign_request_dyn(ctx, req, credential, expires_in)
179 .await
180 }
181}
182
183pub struct ProvideCredentialChain<C> {
219 providers: Vec<Box<dyn ProvideCredentialDyn<Credential = C>>>,
220}
221
222impl<C> ProvideCredentialChain<C>
223where
224 C: Send + Sync + Unpin + 'static,
225{
226 pub fn new() -> Self {
228 Self {
229 providers: Vec::new(),
230 }
231 }
232
233 pub fn push(mut self, provider: impl ProvideCredential<Credential = C> + 'static) -> Self {
235 self.providers.push(Box::new(provider));
236 self
237 }
238
239 pub fn push_front(
243 mut self,
244 provider: impl ProvideCredential<Credential = C> + 'static,
245 ) -> Self {
246 self.providers.insert(0, Box::new(provider));
247 self
248 }
249
250 pub fn from_vec(providers: Vec<Box<dyn ProvideCredentialDyn<Credential = C>>>) -> Self {
252 Self { providers }
253 }
254
255 pub fn len(&self) -> usize {
257 self.providers.len()
258 }
259
260 pub fn is_empty(&self) -> bool {
262 self.providers.is_empty()
263 }
264}
265
266impl<C> Default for ProvideCredentialChain<C>
267where
268 C: Send + Sync + Unpin + 'static,
269{
270 fn default() -> Self {
271 Self::new()
272 }
273}
274
275impl<C> Debug for ProvideCredentialChain<C>
276where
277 C: Send + Sync + Unpin + 'static,
278{
279 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
280 f.debug_struct("ProvideCredentialChain")
281 .field("providers_count", &self.providers.len())
282 .finish()
283 }
284}
285
286impl<C> ProvideCredential for ProvideCredentialChain<C>
287where
288 C: Send + Sync + Unpin + 'static,
289{
290 type Credential = C;
291
292 async fn provide_credential(&self, ctx: &Context) -> Result<Option<Self::Credential>> {
293 for provider in &self.providers {
294 log::debug!("Trying credential provider: {provider:?}");
295
296 match provider.provide_credential_dyn(ctx).await {
297 Ok(Some(cred)) => {
298 log::debug!("Successfully loaded credential from provider: {provider:?}");
299 return Ok(Some(cred));
300 }
301 Ok(None) => {
302 log::debug!("No credential found in provider: {provider:?}");
303 continue;
304 }
305 Err(e) => {
306 log::warn!("Error loading credential from provider {provider:?}: {e:?}");
307 continue;
309 }
310 }
311 }
312
313 Ok(None)
314 }
315}