macp_auth/auth/resolvers/
static_bearer.rs1use crate::auth::resolver::{AuthError, AuthResolver, ResolvedIdentity};
2use crate::security::AuthIdentity;
3use std::collections::HashMap;
4use tonic::metadata::MetadataMap;
5
6pub struct StaticBearerResolver {
9 identities: HashMap<String, AuthIdentity>,
10}
11
12impl StaticBearerResolver {
13 pub fn new(identities: HashMap<String, AuthIdentity>) -> Self {
14 tracing::info!(
15 count = identities.len(),
16 "static bearer resolver initialized"
17 );
18 Self { identities }
19 }
20
21 fn extract_bearer(metadata: &MetadataMap) -> Option<String> {
22 metadata
23 .get("authorization")
24 .and_then(|v| v.to_str().ok())
25 .and_then(|v| v.strip_prefix("Bearer "))
26 .map(str::to_string)
27 .or_else(|| {
28 metadata
29 .get("x-macp-token")
30 .and_then(|v| v.to_str().ok())
31 .map(str::to_string)
32 })
33 }
34}
35
36#[async_trait::async_trait]
37impl AuthResolver for StaticBearerResolver {
38 fn name(&self) -> &str {
39 "static_bearer"
40 }
41
42 async fn resolve(&self, metadata: &MetadataMap) -> Result<Option<ResolvedIdentity>, AuthError> {
43 let token = match Self::extract_bearer(metadata) {
44 Some(t) => t,
45 None => return Ok(None),
46 };
47
48 if token.contains('.') {
50 return Ok(None);
51 }
52
53 match self.identities.get(&token) {
54 Some(identity) => Ok(Some(ResolvedIdentity {
55 sender: identity.sender.clone(),
56 allowed_modes: identity.allowed_modes.clone(),
57 can_start_sessions: identity.can_start_sessions,
58 max_open_sessions: identity.max_open_sessions,
59 can_manage_mode_registry: identity.can_manage_mode_registry,
60 is_observer: identity.is_observer,
61 resolver: "static_bearer".to_string(),
62 })),
63 None => Err(AuthError::InvalidCredential(
64 "token not found in identity map".to_string(),
65 )),
66 }
67 }
68}