Skip to main content

static_authn_plugin/domain/
client.rs

1//! Client implementation for the static `AuthN` resolver plugin.
2//!
3//! Implements `AuthNResolverPluginClient` using the domain service.
4
5use async_trait::async_trait;
6use authn_resolver_sdk::{
7    AuthNResolverError, AuthNResolverPluginClient, AuthenticationResult, ClientCredentialsRequest,
8};
9
10use super::service::Service;
11
12#[async_trait]
13impl AuthNResolverPluginClient for Service {
14    async fn authenticate(
15        &self,
16        bearer_token: &str,
17    ) -> Result<AuthenticationResult, AuthNResolverError> {
18        self.authenticate(bearer_token)
19            .ok_or_else(|| AuthNResolverError::Unauthorized("invalid token".to_owned()))
20    }
21
22    async fn exchange_client_credentials(
23        &self,
24        request: &ClientCredentialsRequest,
25    ) -> Result<AuthenticationResult, AuthNResolverError> {
26        self.exchange_client_credentials(request).ok_or_else(|| {
27            AuthNResolverError::TokenAcquisitionFailed("invalid client credentials".to_owned())
28        })
29    }
30}
31
32#[cfg(test)]
33#[cfg_attr(coverage_nightly, coverage(off))]
34mod tests {
35    use secrecy::SecretString;
36
37    use super::*;
38    use crate::config::{IdentityConfig, S2sCredentialMapping, StaticAuthNPluginConfig};
39
40    #[tokio::test]
41    async fn plugin_trait_accept_all_succeeds() {
42        let service = Service::from_config(&StaticAuthNPluginConfig::default());
43        let plugin: &dyn AuthNResolverPluginClient = &service;
44
45        let result = plugin.authenticate("any-token").await;
46        assert!(result.is_ok());
47    }
48
49    #[tokio::test]
50    async fn plugin_trait_empty_token_unauthorized() {
51        let service = Service::from_config(&StaticAuthNPluginConfig::default());
52        let plugin: &dyn AuthNResolverPluginClient = &service;
53
54        let result = plugin.authenticate("").await;
55        assert!(result.is_err());
56        match result.unwrap_err() {
57            AuthNResolverError::Unauthorized(_) => {}
58            other => panic!("Expected Unauthorized, got: {other:?}"),
59        }
60    }
61
62    #[tokio::test]
63    async fn plugin_trait_s2s_valid_credentials() {
64        let cfg = StaticAuthNPluginConfig {
65            s2s_credentials: vec![S2sCredentialMapping {
66                client_id: "svc".to_owned(),
67                client_secret: SecretString::from("secret"),
68                identity: IdentityConfig::default(),
69            }],
70            ..StaticAuthNPluginConfig::default()
71        };
72        let service = Service::from_config(&cfg);
73        let plugin: &dyn AuthNResolverPluginClient = &service;
74
75        let request = ClientCredentialsRequest {
76            client_id: "svc".to_owned(),
77            client_secret: SecretString::from("secret"),
78            scopes: vec![],
79        };
80        let result = plugin.exchange_client_credentials(&request).await;
81        assert!(result.is_ok());
82    }
83
84    #[tokio::test]
85    async fn plugin_trait_s2s_invalid_credentials() {
86        let service = Service::from_config(&StaticAuthNPluginConfig::default());
87        let plugin: &dyn AuthNResolverPluginClient = &service;
88
89        let request = ClientCredentialsRequest {
90            client_id: "unknown".to_owned(),
91            client_secret: SecretString::from("bad"),
92            scopes: vec![],
93        };
94        let result = plugin.exchange_client_credentials(&request).await;
95        assert!(result.is_err());
96        match result.unwrap_err() {
97            AuthNResolverError::TokenAcquisitionFailed(_) => {}
98            other => panic!("Expected TokenAcquisitionFailed, got: {other:?}"),
99        }
100    }
101}