rmcp_openapi/security/
observer.rs

1use crate::config::Authorization;
2use tracing::{debug, trace, warn};
3
4/// Observes and logs security-related decisions
5pub struct SecurityObserver<'a> {
6    authorization: &'a Authorization,
7}
8
9impl<'a> SecurityObserver<'a> {
10    /// Create a new security observer with the given authorization
11    pub fn new(authorization: &'a Authorization) -> Self {
12        Self { authorization }
13    }
14
15    /// Observe and log an authorization decision for a request
16    pub fn observe_request(&self, operation_id: &str, has_auth: bool, requires_auth: bool) {
17        match self.authorization {
18            Authorization::None if has_auth => {
19                debug!(
20                    operation_id,
21                    "Authorization header stripped (MCP-compliant mode)"
22                );
23            }
24            #[cfg(feature = "authorization-token-passthrough")]
25            Authorization::PassthroughWarn(_) if has_auth => {
26                debug!(
27                    operation_id,
28                    "Forwarding Authorization header (passthrough mode)"
29                );
30            }
31            #[cfg(feature = "authorization-token-passthrough")]
32            Authorization::PassthroughSilent(_) => {
33                trace!(operation_id, has_auth, "Processing request");
34            }
35            _ => {
36                trace!(operation_id, has_auth, requires_auth, "Processing request");
37            }
38        }
39
40        // Only warn when there's a potential issue
41        if requires_auth && !has_auth {
42            warn!(
43                operation_id,
44                "OpenAPI spec requires auth but no Authorization header present"
45            );
46        }
47    }
48
49    /// Log the authorization mode at startup
50    pub fn log_startup(&self) {
51        match self.authorization {
52            Authorization::None => {
53                tracing::info!("Authorization mode: compliant (headers will not be forwarded)");
54            }
55            #[cfg(feature = "authorization-token-passthrough")]
56            Authorization::PassthroughWarn(_) => {
57                tracing::warn!(
58                    "Authorization mode: passthrough (non-MCP-compliant) - \
59                     Authorization headers WILL be forwarded to backend APIs. See SECURITY.md"
60                );
61            }
62            #[cfg(feature = "authorization-token-passthrough")]
63            Authorization::PassthroughSilent(_) => {
64                tracing::info!("Authorization mode: passthrough-silent");
65            }
66        }
67    }
68}