Skip to main content

macp_auth/auth/
chain.rs

1use super::resolver::AuthResolver;
2use crate::security::AuthIdentity;
3use macp_core::error::MacpError;
4use tonic::metadata::MetadataMap;
5
6pub struct AuthResolverChain {
7    resolvers: Vec<Box<dyn AuthResolver>>,
8}
9
10impl AuthResolverChain {
11    pub fn new(resolvers: Vec<Box<dyn AuthResolver>>) -> Self {
12        let names: Vec<&str> = resolvers.iter().map(|r| r.name()).collect();
13        tracing::info!(chain = ?names, "auth resolver chain initialized");
14        Self { resolvers }
15    }
16
17    pub async fn authenticate(&self, metadata: &MetadataMap) -> Result<AuthIdentity, MacpError> {
18        for resolver in &self.resolvers {
19            match resolver.resolve(metadata).await {
20                Ok(Some(identity)) => {
21                    tracing::debug!(
22                        resolver = resolver.name(),
23                        sender = %identity.sender,
24                        "authenticated"
25                    );
26                    return Ok(identity.into());
27                }
28                Ok(None) => continue,
29                Err(e) => {
30                    tracing::warn!(
31                        resolver = resolver.name(),
32                        error = %e,
33                        "auth resolver rejected credential"
34                    );
35                    return Err(MacpError::Unauthenticated);
36                }
37            }
38        }
39        Err(MacpError::Unauthenticated)
40    }
41}