mcp_kit/auth/
composite.rs1use crate::{
2 auth::{
3 credentials::Credentials,
4 provider::{AuthFuture, AuthProvider, DynAuthProvider},
5 },
6 error::McpError,
7};
8
9pub struct CompositeAuthProvider {
26 providers: Vec<DynAuthProvider>,
27}
28
29impl CompositeAuthProvider {
30 pub fn new(providers: Vec<DynAuthProvider>) -> Self {
32 Self { providers }
33 }
34}
35
36impl AuthProvider for CompositeAuthProvider {
37 fn authenticate<'a>(&'a self, credentials: &'a Credentials) -> AuthFuture<'a> {
38 Box::pin(async move {
39 let mut last_err: Option<McpError> = None;
40
41 for provider in &self.providers {
42 if !provider.accepts(credentials) {
43 continue;
44 }
45 match provider.authenticate(credentials).await {
46 Ok(identity) => return Ok(identity),
47 Err(e) => last_err = Some(e),
48 }
49 }
50
51 Err(last_err.unwrap_or_else(|| {
52 McpError::Unauthorized(format!(
53 "no provider accepts '{}' credentials",
54 credentials.kind()
55 ))
56 }))
57 })
58 }
59
60 fn accepts(&self, credentials: &Credentials) -> bool {
61 self.providers.iter().any(|p| p.accepts(credentials))
62 }
63}
64
65pub trait IntoDynProvider: AuthProvider + Sized {
68 fn into_dyn(self) -> DynAuthProvider {
69 std::sync::Arc::new(self)
70 }
71}
72
73impl<T: AuthProvider> IntoDynProvider for T {}