tower_oauth2_resource_server/
builder.rs

1use std::{marker::PhantomData, sync::Arc};
2
3use serde::de::DeserializeOwned;
4
5use crate::{
6    auth_resolver::{AuthorizerResolver, IssuerAuthorizerResolver, SingleAuthorizerResolver},
7    error::StartupError,
8    server::OAuth2ResourceServer,
9    tenant::TenantConfiguration,
10};
11
12#[derive(Debug)]
13pub struct OAuth2ResourceServerBuilder<Claims> {
14    tenant_configurations: Vec<TenantConfiguration>,
15    auth_resolver: Option<Arc<dyn AuthorizerResolver<Claims>>>,
16    phantom: PhantomData<Claims>,
17}
18
19impl<Claims> OAuth2ResourceServer<Claims>
20where
21    Claims: Clone + DeserializeOwned + Send + Sync + 'static,
22{
23    pub fn builder() -> OAuth2ResourceServerBuilder<Claims> {
24        OAuth2ResourceServerBuilder::new()
25    }
26}
27
28impl<Claims> OAuth2ResourceServerBuilder<Claims> {
29    fn new() -> Self {
30        OAuth2ResourceServerBuilder::<Claims> {
31            tenant_configurations: Vec::new(),
32            auth_resolver: None,
33            phantom: PhantomData,
34        }
35    }
36}
37
38impl<Claims> OAuth2ResourceServerBuilder<Claims>
39where
40    Claims: Clone + DeserializeOwned + Send + Sync + 'static,
41{
42    /// Add a tenant (authorization server).
43    pub fn add_tenant(mut self, tenant_configuration: TenantConfiguration) -> Self {
44        self.tenant_configurations.push(tenant_configuration);
45        self
46    }
47
48    /// Add multiple tenants (authorization servers).
49    pub fn add_tenants(mut self, tenant_configurations: Vec<TenantConfiguration>) -> Self {
50        self.tenant_configurations.extend(tenant_configurations);
51        self
52    }
53
54    /// Provide a custom authorization resolver.
55    ///
56    /// Only needs to be provided if the default resolver is not sufficient.
57    ///
58    /// See [AuthorizerResolver] for more information.
59    pub fn auth_resolver(mut self, auth_resolver: Arc<dyn AuthorizerResolver<Claims>>) -> Self {
60        self.auth_resolver = Some(auth_resolver);
61        self
62    }
63
64    /// Construct an OAuth2ResourceServer.
65    ///
66    /// During construction the OIDC Provider Configuration endpoint of the
67    /// authorization server might be queried.
68    /// Thus, the operation can fail and therefore returns a Result.
69    pub async fn build(self) -> Result<OAuth2ResourceServer<Claims>, StartupError> {
70        if self.tenant_configurations.is_empty() {
71            return Err(StartupError::InvalidParameter(
72                "At least one TenantConfiguration is required".to_owned(),
73            ));
74        }
75        let num_tenants = self.tenant_configurations.len();
76        let auth_resolver = self.auth_resolver.unwrap_or_else(|| {
77            if num_tenants == 1 {
78                Arc::new(SingleAuthorizerResolver {})
79            } else {
80                Arc::new(IssuerAuthorizerResolver {})
81            }
82        });
83        OAuth2ResourceServer::new(self.tenant_configurations, auth_resolver).await
84    }
85}
86
87impl<Claims> Default for OAuth2ResourceServerBuilder<Claims> {
88    fn default() -> Self {
89        Self::new()
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use serde::Deserialize;
96
97    use super::*;
98
99    #[derive(Clone, Debug, Deserialize)]
100    struct Claims {}
101
102    #[tokio::test]
103    async fn should_require_tenant_configurations() {
104        let result = OAuth2ResourceServerBuilder::<Claims>::new().build().await;
105        assert!(result.is_err());
106        assert_eq!(
107            result.unwrap_err(),
108            StartupError::InvalidParameter(
109                "At least one TenantConfiguration is required".to_owned()
110            )
111        )
112    }
113}