use std::time::SystemTime;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum TrustContext {
Unauthenticated,
BearerToken {
kid: String,
aud: String,
sub: String,
scopes: Vec<String>,
tenant_id: String,
},
Mtls {
cn: String,
fingerprint_sha256: [u8; 32],
},
Studio {
user: String,
scope: StudioScope,
step_up_until: Option<SystemTime>,
},
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum StudioScope {
ReadOnly,
Operator,
Admin,
}
impl TrustContext {
pub fn is_authenticated(&self) -> bool {
!matches!(self, TrustContext::Unauthenticated)
}
pub fn is_service_bearer(&self) -> bool {
matches!(
self,
TrustContext::BearerToken { scopes, .. } if scopes.iter().any(|s| s == "service")
)
}
pub fn tenant_id(&self) -> Option<&str> {
match self {
TrustContext::BearerToken { tenant_id, .. } => Some(tenant_id.as_str()),
_ => None,
}
}
}
#[async_trait::async_trait]
pub trait TrustExtractor: Send + Sync {
async fn extract(&self, parts: &http::request::Parts) -> Result<TrustContext, TrustError>;
}
#[derive(Debug, thiserror::Error)]
pub enum TrustError {
#[error("missing authentication credentials")]
Missing,
#[error("invalid bearer token: {0}")]
InvalidBearer(String),
#[error("invalid mTLS certificate: {0}")]
InvalidMtls(String),
}