feat: Add SSH authentication interceptor and update proto definitions

This commit is contained in:
GW_MC
2026-03-21 03:06:56 +00:00
parent 261e6b1bdb
commit 2fcdc7d0df
5 changed files with 82 additions and 86 deletions

View File

@@ -0,0 +1 @@
pub mod ssh_auth;

View File

@@ -0,0 +1,49 @@
use std::sync::Arc;
use tonic::{Request, Status, async_trait, transport::CertificateDer};
use tonic_async_interceptor::{AsyncInterceptor, AsyncInterceptorLayer, async_interceptor};
pub fn create_ssh_auth_interceptor(
certificate_provider: Arc<dyn CertificateValidationProvider>,
) -> AsyncInterceptorLayer<SshAuthInterceptor> {
async_interceptor(SshAuthInterceptor::new(certificate_provider))
}
#[derive(Clone)]
pub struct SshAuthInterceptor {
certificate_provider: Arc<dyn CertificateValidationProvider>,
}
#[async_trait]
pub trait CertificateValidationProvider: Send + Sync {
async fn is_authorized(&self, certs: &Arc<Vec<CertificateDer<'_>>>) -> Result<bool, Status>;
}
impl AsyncInterceptor for SshAuthInterceptor {
type Future =
std::pin::Pin<Box<dyn std::future::Future<Output = Result<Request<()>, Status>> + Send>>;
fn call(&mut self, req: Request<()>) -> Self::Future {
let this = self.clone();
Box::pin(async move { this.authenticate(req).await })
}
}
impl SshAuthInterceptor {
pub fn new(certificate_provider: Arc<dyn CertificateValidationProvider>) -> Self {
SshAuthInterceptor {
certificate_provider,
}
}
async fn authenticate(&self, req: Request<()>) -> Result<Request<()>, Status> {
let certs = req.peer_certs().ok_or(Status::unauthenticated("No cert"))?;
let is_authorized = self.certificate_provider.is_authorized(&certs).await?;
if is_authorized {
Ok(req)
} else {
Err(Status::permission_denied("Blocked"))
}
}
}