use tonic::service::Interceptor;
use tonic::Status;
#[derive(Clone, Debug)]
pub enum Credentials {
BearerToken(String),
DevMode(DevModeCredentials),
None,
}
#[derive(Clone, Debug, Default)]
pub struct DevModeCredentials {
pub subject: String,
pub email: Option<String>,
pub display_name: Option<String>,
pub grants: Option<String>,
}
impl DevModeCredentials {
pub fn new(subject: impl Into<String>) -> Self {
Self {
subject: subject.into(),
..Default::default()
}
}
pub fn with_email(mut self, email: impl Into<String>) -> Self {
self.email = Some(email.into());
self
}
pub fn with_display_name(mut self, display_name: impl Into<String>) -> Self {
self.display_name = Some(display_name.into());
self
}
pub fn with_grants(mut self, grants: impl Into<String>) -> Self {
self.grants = Some(grants.into());
self
}
}
#[derive(Clone, Debug)]
pub struct AuthInterceptor {
credentials: Credentials,
}
impl AuthInterceptor {
pub fn new(credentials: Credentials) -> Self {
Self { credentials }
}
}
impl Interceptor for AuthInterceptor {
fn call(&mut self, mut request: tonic::Request<()>) -> Result<tonic::Request<()>, Status> {
let metadata = request.metadata_mut();
match &self.credentials {
Credentials::BearerToken(token) => {
if let Ok(value) = format!("Bearer {}", token).parse() {
metadata.insert("authorization", value);
}
}
Credentials::DevMode(creds) => {
if let Ok(value) = creds.subject.parse() {
metadata.insert("x-dev-subject", value);
}
if let Some(email) = &creds.email {
if let Ok(value) = email.parse() {
metadata.insert("x-dev-email", value);
}
}
if let Some(name) = &creds.display_name {
if let Ok(value) = name.parse() {
metadata.insert("x-dev-display-name", value);
}
}
if let Some(grants) = &creds.grants {
if let Ok(value) = grants.parse() {
metadata.insert("x-dev-grants", value);
}
}
}
Credentials::None => {}
}
Ok(request)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dev_mode_credentials_builder() {
let creds = DevModeCredentials::new("user@example.com")
.with_email("user@example.com")
.with_display_name("Test User")
.with_grants(r#"{"global": ["reader"]}"#);
assert_eq!(creds.subject, "user@example.com");
assert_eq!(creds.email, Some("user@example.com".to_string()));
assert_eq!(creds.display_name, Some("Test User".to_string()));
assert_eq!(creds.grants, Some(r#"{"global": ["reader"]}"#.to_string()));
}
#[test]
fn test_credentials_clone() {
let creds = Credentials::BearerToken("test-token".to_string());
let cloned = creds.clone();
assert!(matches!(cloned, Credentials::BearerToken(t) if t == "test-token"));
}
}