use async_trait::async_trait;
use std::sync::Arc;
use vti_common::auth::backend::{AuthBackend, AuthError, RoleResolution};
use vti_common::auth::handlers::KeyspaceSessionStore;
use vti_common::auth::jwt::JwtKeys;
use crate::acl::Role;
use crate::error::AppError;
use crate::server::AppState;
pub struct VtcAuthBackend {
state: Arc<AppState>,
sessions: KeyspaceSessionStore,
jwt_keys: Arc<JwtKeys>,
challenge_ttl: u64,
access_token_ttl: u64,
refresh_token_ttl: u64,
}
impl VtcAuthBackend {
pub async fn from_state(state: &AppState) -> Result<Self, AppError> {
let jwt_keys = state
.jwt_keys
.clone()
.ok_or_else(|| AppError::Internal("JWT keys not configured".to_string()))?;
let sessions = KeyspaceSessionStore::new(state.sessions_ks.clone());
let (challenge_ttl, access_token_ttl, refresh_token_ttl) = {
let cfg = state.config.read().await;
(
cfg.auth.challenge_ttl,
cfg.auth.access_token_expiry,
cfg.auth.refresh_token_expiry,
)
};
Ok(Self {
state: Arc::new(state.clone()),
sessions,
jwt_keys,
challenge_ttl,
access_token_ttl,
refresh_token_ttl,
})
}
}
#[async_trait]
impl AuthBackend for VtcAuthBackend {
type Store = KeyspaceSessionStore;
type Error = AppError;
type Role = Role;
fn sessions(&self) -> &Self::Store {
&self.sessions
}
async fn mint_access_token(
&self,
subject: &str,
session_id: &str,
role: &Self::Role,
contexts: &[String],
amr: &[String],
acr: &str,
tee_attested: bool,
ttl_secs: u64,
) -> Result<String, Self::Error> {
let claims = self
.jwt_keys
.new_claims(
subject.to_string(),
session_id.to_string(),
role.to_string(),
contexts.to_vec(),
ttl_secs,
tee_attested,
)
.with_aal(amr.to_vec(), acr.to_string());
self.jwt_keys
.encode(&claims)
.map_err(|e| AppError::Internal(format!("jwt encode failed: {e:?}")))
}
async fn check_acl(&self, did: &str) -> Result<RoleResolution<Self::Role>, Self::Error> {
let (role, allowed_contexts) =
vti_common::acl::check_acl_full(&self.state.acl_ks, did).await?;
Ok(RoleResolution::with_contexts(role, allowed_contexts))
}
fn challenge_ttl(&self) -> u64 {
self.challenge_ttl
}
fn access_token_ttl(&self) -> u64 {
self.access_token_ttl
}
fn refresh_token_ttl(&self) -> u64 {
self.refresh_token_ttl
}
}
const _: fn() = || {
fn assert_from_authentication_error<E: From<AuthError>>() {}
assert_from_authentication_error::<AppError>();
};