use anyhow::Result;
use chrono::{DateTime, Utc};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AuthType {
ApiKey,
Oidc,
}
#[derive(Debug, Clone)]
pub struct AuthContext {
pub subject: String,
pub email: Option<String>,
pub issuer: String,
pub audience: Option<String>,
pub expires_at: Option<DateTime<Utc>>,
pub auth_type: AuthType,
pub is_admin: bool,
pub allow_delegation: bool,
}
pub trait RequestParts: Send + Sync {
fn authorization_header(&self) -> Option<&str>;
fn bearer_token(&self) -> Option<&str> {
self.authorization_header()
.and_then(|h| h.strip_prefix("Bearer "))
}
fn get_header(&self, name: &str) -> Option<&str>;
fn method(&self) -> Option<&str>;
fn uri(&self) -> Option<&str>;
}
pub struct HttpRequestParts {
pub headers: http::HeaderMap,
pub method: http::Method,
pub uri: http::Uri,
}
impl RequestParts for HttpRequestParts {
fn authorization_header(&self) -> Option<&str> {
self.headers
.get(http::header::AUTHORIZATION)
.and_then(|h| h.to_str().ok())
}
fn get_header(&self, name: &str) -> Option<&str> {
self.headers.get(name).and_then(|h| h.to_str().ok())
}
fn method(&self) -> Option<&str> {
Some(self.method.as_str())
}
fn uri(&self) -> Option<&str> {
Some(self.uri.path())
}
}
pub struct GrpcRequestParts {
pub metadata: tonic::metadata::MetadataMap,
}
impl RequestParts for GrpcRequestParts {
fn authorization_header(&self) -> Option<&str> {
self.metadata
.get("authorization")
.and_then(|h| h.to_str().ok())
}
fn get_header(&self, name: &str) -> Option<&str> {
self.metadata.get(name).and_then(|h| h.to_str().ok())
}
fn method(&self) -> Option<&str> {
None
}
fn uri(&self) -> Option<&str> {
None
}
}
#[async_trait::async_trait]
pub trait AuthProvider: Send + Sync {
async fn validate_request(&self, parts: &dyn RequestParts) -> Result<AuthContext>;
}