1use crate::Result;
4pub use crate::message::AuthCredentials;
5
6#[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 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 pub fn has_permission(&self, permission: &str) -> bool {
26 self.permissions.iter().any(|p| p == permission)
27 }
28
29 pub fn is_admin(&self) -> bool {
31 self.has_permission("admin")
32 }
33
34 pub fn is_authenticated_to(&self, tenant_id: &str) -> bool {
36 self.tenant_id == tenant_id
37 }
38}
39
40pub fn api_key(key: String) -> AuthCredentials {
42 AuthCredentials::ApiKey { key }
43}
44
45pub fn jwt(token: String) -> AuthCredentials {
47 AuthCredentials::Jwt { token }
48}
49
50pub fn basic(username: String, password: String) -> AuthCredentials {
52 AuthCredentials::Basic { username, password }
53}
54
55pub 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}