use std::collections::HashMap;
use osproxy_core::PrincipalId;
use osproxy_spi::{Action, AuthError, Authenticator, Authorizer, ClientCredentials, Principal};
#[derive(Debug, Default, Clone, Copy)]
pub struct AllowAllAuthorizer;
impl Authorizer for AllowAllAuthorizer {
async fn authorize(&self, _principal: &Principal, _action: &Action) -> Result<(), AuthError> {
Ok(())
}
}
#[derive(Debug, Default)]
pub struct ReferenceAuthenticator {
tokens: HashMap<String, String>,
}
impl ReferenceAuthenticator {
#[must_use]
pub fn new(tokens: HashMap<String, String>) -> Self {
Self { tokens }
}
#[must_use]
pub fn dev() -> Self {
Self::default()
}
fn is_dev(&self) -> bool {
self.tokens.is_empty()
}
}
impl Authenticator for ReferenceAuthenticator {
async fn authenticate(&self, creds: &ClientCredentials) -> Result<Principal, AuthError> {
if self.is_dev() {
let id = creds
.client_cert_subject
.as_deref()
.or(creds.bearer_token.as_deref())
.unwrap_or("anonymous");
return Ok(Principal::new(PrincipalId::from(id)));
}
let token = creds
.bearer_token
.as_deref()
.ok_or(AuthError::MissingCredentials)?;
self.tokens
.get(token)
.map(|pid| Principal::new(PrincipalId::from(pid.as_str())))
.ok_or(AuthError::InvalidCredentials)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn dev_mode_accepts_anyone() {
let auth = ReferenceAuthenticator::dev();
let p = auth
.authenticate(&ClientCredentials::default())
.await
.unwrap();
assert_eq!(p.id().as_str(), "anonymous");
let p = auth
.authenticate(&ClientCredentials::bearer("svc-x"))
.await
.unwrap();
assert_eq!(p.id().as_str(), "svc-x");
}
#[tokio::test]
async fn configured_tokens_are_enforced() {
let mut tokens = HashMap::new();
tokens.insert("s3cr3t".to_owned(), "svc-ingest".to_owned());
let auth = ReferenceAuthenticator::new(tokens);
let p = auth
.authenticate(&ClientCredentials::bearer("s3cr3t"))
.await
.unwrap();
assert_eq!(p.id().as_str(), "svc-ingest");
assert_eq!(
auth.authenticate(&ClientCredentials::bearer("wrong")).await,
Err(AuthError::InvalidCredentials)
);
assert_eq!(
auth.authenticate(&ClientCredentials::default()).await,
Err(AuthError::MissingCredentials)
);
}
}