Skip to main content

rs_adk/auth/
handler.rs

1//! Auth handler — orchestrates auth flows by retrieving stored credentials
2//! and generating auth requests.
3
4use super::config::AuthConfig;
5use super::credential::AuthCredential;
6use crate::state::State;
7
8/// Orchestrates auth flows: retrieves stored credentials and generates auth requests.
9pub struct AuthHandler {
10    config: AuthConfig,
11}
12
13impl AuthHandler {
14    /// Create a new auth handler with the given configuration.
15    pub fn new(config: AuthConfig) -> Self {
16        Self { config }
17    }
18
19    /// Retrieve the auth credential from state (looks up "temp:{credential_key}").
20    pub fn get_auth_response(&self, state: &State) -> Option<AuthCredential> {
21        let key = format!("temp:{}", self.config.credential_key);
22        state
23            .get_raw(&key)
24            .and_then(|v| serde_json::from_value(v).ok())
25    }
26
27    /// Generate an auth request config for the client to fulfill (e.g. OAuth2 redirect).
28    pub fn generate_auth_request(&self) -> AuthConfig {
29        self.config.clone()
30    }
31
32    /// Get the auth config.
33    pub fn config(&self) -> &AuthConfig {
34        &self.config
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41    use crate::auth::credential::{AuthCredentialType, OAuth2Auth};
42    use crate::auth::schemes::{AuthScheme, OAuthGrantType};
43
44    fn test_config() -> AuthConfig {
45        AuthConfig {
46            auth_scheme: AuthScheme::OAuth2 {
47                grant_type: Some(OAuthGrantType::AuthorizationCode),
48                authorization_url: Some("https://example.com/authorize".into()),
49                token_url: Some("https://example.com/token".into()),
50                scopes: None,
51            },
52            raw_auth_credential: None,
53            exchanged_auth_credential: None,
54            credential_key: "my-oauth-cred".into(),
55        }
56    }
57
58    fn test_credential() -> AuthCredential {
59        AuthCredential {
60            auth_type: AuthCredentialType::OAuth2,
61            resource_ref: None,
62            api_key: None,
63            http: None,
64            oauth2: Some(OAuth2Auth {
65                client_id: Some("client-123".into()),
66                client_secret: None,
67                auth_uri: None,
68                token_uri: None,
69                redirect_uri: None,
70                auth_code: None,
71                access_token: Some("ya29.test-token".into()),
72                refresh_token: None,
73                expires_at: None,
74                scopes: None,
75                auth_response_uri: None,
76            }),
77            service_account: None,
78        }
79    }
80
81    #[test]
82    fn get_auth_response_found() {
83        let state = State::new();
84        let cred = test_credential();
85        state.set("temp:my-oauth-cred", &cred);
86
87        let handler = AuthHandler::new(test_config());
88        let result = handler.get_auth_response(&state);
89        assert!(result.is_some());
90        let result = result.unwrap();
91        assert_eq!(result.auth_type, AuthCredentialType::OAuth2);
92        assert_eq!(
93            result.oauth2.as_ref().unwrap().access_token.as_deref(),
94            Some("ya29.test-token")
95        );
96    }
97
98    #[test]
99    fn get_auth_response_not_found() {
100        let state = State::new();
101        let handler = AuthHandler::new(test_config());
102        let result = handler.get_auth_response(&state);
103        assert!(result.is_none());
104    }
105
106    #[test]
107    fn generate_auth_request_returns_config_clone() {
108        let config = test_config();
109        let handler = AuthHandler::new(config.clone());
110        let request = handler.generate_auth_request();
111
112        assert_eq!(request.credential_key, config.credential_key);
113        // Verify it's a separate clone by checking the values match
114        match (&request.auth_scheme, &config.auth_scheme) {
115            (
116                AuthScheme::OAuth2 {
117                    authorization_url: a_url,
118                    ..
119                },
120                AuthScheme::OAuth2 {
121                    authorization_url: b_url,
122                    ..
123                },
124            ) => {
125                assert_eq!(a_url, b_url);
126            }
127            _ => panic!("expected OAuth2 scheme"),
128        }
129    }
130
131    #[test]
132    fn config_accessor() {
133        let config = test_config();
134        let handler = AuthHandler::new(config);
135        assert_eq!(handler.config().credential_key, "my-oauth-cred");
136    }
137}