pub mod anonymous;
#[cfg(feature = "oauth")]
pub mod oauth;
pub mod static_token;
pub use anonymous::AnonymousAuth;
#[cfg(feature = "oauth")]
pub use oauth::{FreshToken, OAuthRefreshAuth, TokenSource};
pub use static_token::StaticTokenAuth;
use crate::error::Result;
use crate::resource::Resource;
use std::borrow::Cow;
use std::future::Future;
use std::pin::Pin;
#[derive(Clone, Debug)]
#[non_exhaustive]
pub enum Credential<'a> {
Anonymous,
Bearer(Cow<'a, str>),
Header {
name: &'static str,
value: Cow<'a, str>,
},
Presigned,
}
pub trait AuthProvider: Send + Sync {
type RefreshFuture<'a>: Future<Output = Result<()>> + Send + 'a
where
Self: 'a;
fn credential(&self, resource: &Resource) -> Credential<'_>;
fn needs_refresh(&self) -> bool {
false
}
fn refresh(&self) -> Self::RefreshFuture<'_>;
}
pub trait DynAuthProvider: Send + Sync {
fn credential(&self, resource: &Resource) -> Credential<'_>;
fn needs_refresh(&self) -> bool;
fn refresh_boxed(&self) -> Pin<Box<dyn Future<Output = Result<()>> + Send + '_>>;
}
impl<A: AuthProvider> DynAuthProvider for A {
fn credential(&self, resource: &Resource) -> Credential<'_> {
AuthProvider::credential(self, resource)
}
fn needs_refresh(&self) -> bool {
AuthProvider::needs_refresh(self)
}
fn refresh_boxed(&self) -> Pin<Box<dyn Future<Output = Result<()>> + Send + '_>> {
Box::pin(self.refresh())
}
}
impl AuthProvider for Box<dyn DynAuthProvider> {
type RefreshFuture<'a>
= Pin<Box<dyn Future<Output = Result<()>> + Send + 'a>>
where
Self: 'a;
fn credential(&self, resource: &Resource) -> Credential<'_> {
(**self).credential(resource)
}
fn needs_refresh(&self) -> bool {
(**self).needs_refresh()
}
fn refresh(&self) -> Self::RefreshFuture<'_> {
(**self).refresh_boxed()
}
}
#[cfg(test)]
mod tests {
use super::*;
use url::Url;
fn resource() -> Resource {
Resource::new(Url::parse("https://x.dev/a").unwrap())
}
#[tokio::test]
async fn dyn_auth_provider_roundtrips() {
let boxed: Box<dyn DynAuthProvider> = Box::new(StaticTokenAuth::bearer("secret"));
let cred = AuthProvider::credential(&boxed, &resource());
assert!(matches!(cred, Credential::Bearer(_)));
assert!(!AuthProvider::needs_refresh(&boxed));
AuthProvider::refresh(&boxed).await.unwrap();
}
}