use async_trait::async_trait;
use std::collections::HashMap;
use crate::domain::{A2AError, core::agent::SecurityScheme};
#[derive(Debug, Clone)]
pub struct AuthContext {
pub scheme_type: String,
pub credential: String,
pub metadata: HashMap<String, String>,
}
impl AuthContext {
pub fn new(scheme_type: String, credential: String) -> Self {
Self {
scheme_type,
credential,
metadata: HashMap::new(),
}
}
pub fn with_metadata(mut self, key: String, value: String) -> Self {
self.metadata.insert(key, value);
self
}
pub fn get_metadata(&self, key: &str) -> Option<&String> {
self.metadata.get(key)
}
}
#[async_trait]
pub trait Authenticator: Send + Sync {
async fn authenticate(&self, context: &AuthContext) -> Result<AuthPrincipal, A2AError>;
fn security_scheme(&self) -> &SecurityScheme;
fn validate_context(&self, context: &AuthContext) -> Result<(), A2AError>;
}
#[derive(Debug, Clone)]
pub struct AuthPrincipal {
pub id: String,
pub scheme: String,
pub attributes: HashMap<String, String>,
}
impl AuthPrincipal {
pub fn new(id: String, scheme: String) -> Self {
Self {
id,
scheme,
attributes: HashMap::new(),
}
}
pub fn with_attribute(mut self, key: String, value: String) -> Self {
self.attributes.insert(key, value);
self
}
}
#[async_trait]
pub trait AuthContextExtractor: Send + Sync {
#[cfg(feature = "http-server")]
async fn extract_from_headers(&self, headers: &axum::http::HeaderMap) -> Option<AuthContext>;
#[cfg(not(feature = "http-server"))]
async fn extract_from_headers(
&self,
headers: &std::collections::HashMap<String, String>,
) -> Option<AuthContext>;
async fn extract_from_query(&self, params: &HashMap<String, String>) -> Option<AuthContext>;
async fn extract_from_cookies(&self, cookies: &str) -> Option<AuthContext>;
}
#[async_trait]
pub trait CompositeAuthenticator: Send + Sync {
async fn authenticate_any(&self, contexts: Vec<AuthContext>)
-> Result<AuthPrincipal, A2AError>;
fn supported_schemes(&self) -> Vec<&SecurityScheme>;
}