use std::collections::HashMap;
use std::sync::Arc;
pub trait AuthResolver: Send + Sync {
fn realm(&self) -> &str;
fn headers(&self) -> Vec<(String, String)>;
}
#[derive(Default, Clone)]
pub struct AuthRegistry {
resolvers: HashMap<String, Arc<dyn AuthResolver>>,
}
impl AuthRegistry {
pub fn new() -> Self {
Self::default()
}
pub fn register(&mut self, resolver: Arc<dyn AuthResolver>) -> &mut Self {
self.resolvers
.insert(resolver.realm().to_string(), resolver);
self
}
pub fn get(&self, realm: &str) -> Option<Arc<dyn AuthResolver>> {
self.resolvers.get(realm).cloned()
}
pub fn realms(&self) -> Vec<String> {
self.resolvers.keys().cloned().collect()
}
}
pub struct StaticHeaderAuth {
realm: String,
headers: Vec<(String, String)>,
}
impl StaticHeaderAuth {
pub fn bearer(realm: impl Into<String>, token: impl AsRef<str>) -> Self {
Self {
realm: realm.into(),
headers: vec![(
"Authorization".to_string(),
format!("Bearer {}", token.as_ref()),
)],
}
}
pub fn header(
realm: impl Into<String>,
name: impl Into<String>,
value: impl Into<String>,
) -> Self {
Self {
realm: realm.into(),
headers: vec![(name.into(), value.into())],
}
}
pub fn headers(realm: impl Into<String>, headers: Vec<(String, String)>) -> Self {
Self {
realm: realm.into(),
headers,
}
}
}
impl AuthResolver for StaticHeaderAuth {
fn realm(&self) -> &str {
&self.realm
}
fn headers(&self) -> Vec<(String, String)> {
self.headers.clone()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn register_and_resolve() {
let mut reg = AuthRegistry::new();
reg.register(Arc::new(StaticHeaderAuth::bearer("cds", "secret-token")));
let r = reg.get("cds").expect("cds resolver registered");
assert_eq!(r.realm(), "cds");
assert_eq!(
r.headers(),
vec![(
"Authorization".to_string(),
"Bearer secret-token".to_string()
)]
);
assert!(reg.get("rda").is_none());
}
#[test]
fn credentials_are_only_in_headers_never_the_realm() {
let a = StaticHeaderAuth::header("firms", "X-API-Key", "abc123");
assert_eq!(a.realm(), "firms"); assert_eq!(
a.headers(),
vec![("X-API-Key".to_string(), "abc123".to_string())]
);
}
}