Skip to main content

alibi_plugins/oauth_provider/
extension_authentication.rs

1use super::{OAuthProviderConfig, OAuthProviderPlugin};
2use alibi_core::CallbackContext;
3use alibi_core::endpoint::EndpointError;
4use async_trait::async_trait;
5use serde_json::Value;
6use std::sync::Arc;
7
8#[derive(Debug, Clone)]
9pub struct OAuthExtensionClientAuthentication {
10    pub assertion_types: Option<Vec<String>>,
11    pub strategy: Arc<dyn OAuthClientAuthenticationStrategy>,
12}
13
14pub struct OAuthClientAssertionInput<'a> {
15    pub context: CallbackContext,
16    pub options: &'a OAuthProviderConfig,
17    pub assertion: &'a str,
18    pub assertion_type: &'a str,
19    pub client_id: Option<&'a str>,
20    pub expected_audience: &'a str,
21}
22
23#[derive(Debug, Clone)]
24pub struct OAuthVerifiedClientAssertion {
25    pub client_id: String,
26    pub confirmation: Option<Value>,
27}
28
29#[async_trait]
30pub trait OAuthClientAuthenticationStrategy: Send + Sync + std::fmt::Debug {
31    async fn authenticate(
32        &self,
33        input: OAuthClientAssertionInput<'_>,
34    ) -> Result<OAuthVerifiedClientAssertion, EndpointError>;
35}
36
37impl OAuthProviderPlugin {
38    pub(super) fn supported_auth_methods(&self, include_none: bool) -> Vec<String> {
39        super::unique(
40            include_none
41                .then_some("none")
42                .into_iter()
43                .chain([
44                    "client_secret_basic",
45                    "client_secret_post",
46                    "private_key_jwt",
47                ])
48                .map(str::to_owned)
49                .chain(
50                    self.config
51                        .extensions
52                        .iter()
53                        .flat_map(|extension| extension.client_authentication.keys().cloned()),
54                )
55                .collect(),
56        )
57    }
58    pub(super) fn is_extension_auth_method(&self, method: &str) -> bool {
59        self.config
60            .extensions
61            .iter()
62            .any(|extension| extension.client_authentication.contains_key(method))
63    }
64    pub(super) fn client_authentication_strategy(
65        &self,
66        assertion_type: &str,
67    ) -> Option<(&str, &OAuthExtensionClientAuthentication)> {
68        if assertion_type == "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" {
69            return None;
70        }
71        self.config
72            .extensions
73            .iter()
74            .flat_map(|extension| &extension.client_authentication)
75            .find(|(method, strategy)| {
76                strategy.assertion_types.as_ref().map_or_else(
77                    || method.as_str() == assertion_type,
78                    |types| types.iter().any(|value| value == assertion_type),
79                )
80            })
81            .map(|(method, strategy)| (method.as_str(), strategy))
82    }
83}