Skip to main content

commy_sdk_rust/
auth.rs

1//! Authentication utilities
2
3use crate::Result;
4pub use crate::message::AuthCredentials;
5
6/// Authentication context for a session
7#[derive(Debug, Clone)]
8pub struct AuthContext {
9    pub tenant_id: String,
10    pub permissions: Vec<String>,
11    pub authenticated_at: chrono::DateTime<chrono::Utc>,
12}
13
14impl AuthContext {
15    /// Create a new authentication context
16    pub fn new(tenant_id: String, permissions: Vec<String>) -> Self {
17        Self {
18            tenant_id,
19            permissions,
20            authenticated_at: chrono::Utc::now(),
21        }
22    }
23
24    /// Check if the context has a specific permission
25    pub fn has_permission(&self, permission: &str) -> bool {
26        self.permissions.iter().any(|p| p == permission)
27    }
28
29    /// Check if the context has admin permission
30    pub fn is_admin(&self) -> bool {
31        self.has_permission("admin")
32    }
33
34    /// Check if authenticated to a specific tenant
35    pub fn is_authenticated_to(&self, tenant_id: &str) -> bool {
36        self.tenant_id == tenant_id
37    }
38}
39
40/// Build API key authentication
41pub fn api_key(key: String) -> AuthCredentials {
42    AuthCredentials::ApiKey { key }
43}
44
45/// Build JWT authentication
46pub fn jwt(token: String) -> AuthCredentials {
47    AuthCredentials::Jwt { token }
48}
49
50/// Build basic authentication
51pub fn basic(username: String, password: String) -> AuthCredentials {
52    AuthCredentials::Basic { username, password }
53}
54
55/// Validate a token format (basic validation)
56pub fn validate_token_format(token: &str) -> Result<()> {
57    if token.is_empty() {
58        return Err(crate::error::CommyError::AuthenticationFailed(
59            "Token cannot be empty".to_string(),
60        ));
61    }
62
63    if token.len() > 10000 {
64        return Err(crate::error::CommyError::AuthenticationFailed(
65            "Token is too long".to_string(),
66        ));
67    }
68
69    Ok(())
70}
71
72#[cfg(test)]
73mod tests {
74    use super::*;
75
76    #[test]
77    fn test_auth_context_creation() {
78        let ctx = AuthContext::new("tenant_1".to_string(), vec!["read".to_string()]);
79        assert_eq!(ctx.tenant_id, "tenant_1");
80        assert!(ctx.has_permission("read"));
81    }
82
83    #[test]
84    fn test_has_permission() {
85        let ctx = AuthContext::new(
86            "tenant_1".to_string(),
87            vec!["read".to_string(), "write".to_string()],
88        );
89        assert!(ctx.has_permission("read"));
90        assert!(ctx.has_permission("write"));
91        assert!(!ctx.has_permission("admin"));
92    }
93
94    #[test]
95    fn test_validate_token_format() {
96        assert!(validate_token_format("valid_token").is_ok());
97        assert!(validate_token_format("").is_err());
98    }
99}