pulseengine_mcp_auth/
models.rs

1//! Authentication models
2
3use crate::crypto::hashing::Salt;
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6use std::fmt;
7
8/// API key for authentication with comprehensive metadata
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct ApiKey {
11    /// Unique key identifier (format: lmcp_{role}_{timestamp}_{random})
12    pub id: String,
13    /// Human-readable name/description
14    pub name: String,
15    /// The actual secret token used for authentication
16    pub key: String,
17    /// Secure hash of the secret token (for storage)
18    pub secret_hash: Option<String>,
19    /// Salt used for hashing the secret token
20    pub salt: Option<Salt>,
21    /// Role-based permissions
22    pub role: Role,
23    /// Creation timestamp
24    pub created_at: DateTime<Utc>,
25    /// Optional expiration timestamp
26    pub expires_at: Option<DateTime<Utc>>,
27    /// Last time this key was used
28    pub last_used: Option<DateTime<Utc>>,
29    /// IP address whitelist (empty = all IPs allowed)
30    #[serde(default)]
31    pub ip_whitelist: Vec<String>,
32    /// Is the key currently active
33    pub active: bool,
34    /// Usage count
35    #[serde(default)]
36    pub usage_count: u64,
37}
38
39impl ApiKey {
40    /// Create a new API key with secure random generation
41    pub fn new(
42        name: String,
43        role: Role,
44        expires_at: Option<DateTime<Utc>>,
45        ip_whitelist: Vec<String>,
46    ) -> Self {
47        use crate::crypto::hashing::{generate_salt, hash_api_key};
48        use crate::crypto::keys::{generate_key_id, generate_secure_key};
49
50        let role_str = match &role {
51            Role::Admin => "admin",
52            Role::Operator => "op",
53            Role::Monitor => "mon",
54            Role::Device { .. } => "dev",
55            Role::Custom { .. } => "custom",
56        };
57
58        let id = generate_key_id(role_str);
59        let secret = generate_secure_key();
60
61        // Generate salt and hash for secure storage
62        let salt = generate_salt();
63        let secret_hash = hash_api_key(&secret, &salt);
64
65        Self {
66            id,
67            name,
68            key: secret,
69            secret_hash: Some(secret_hash),
70            salt: Some(salt),
71            role,
72            created_at: Utc::now(),
73            expires_at,
74            last_used: None,
75            ip_whitelist,
76            active: true,
77            usage_count: 0,
78        }
79    }
80
81    /// Check if the key is expired
82    pub fn is_expired(&self) -> bool {
83        if let Some(expires_at) = self.expires_at {
84            Utc::now() > expires_at
85        } else {
86            false
87        }
88    }
89
90    /// Check if the key is valid for use
91    pub fn is_valid(&self) -> bool {
92        self.active && !self.is_expired()
93    }
94
95    /// Update last used timestamp
96    pub fn mark_used(&mut self) {
97        self.last_used = Some(Utc::now());
98        self.usage_count += 1;
99    }
100
101    /// Verify if the provided key matches the stored hash
102    pub fn verify_key(
103        &self,
104        provided_key: &str,
105    ) -> Result<bool, crate::crypto::hashing::HashingError> {
106        use crate::crypto::hashing::verify_api_key;
107
108        if let (Some(ref hash), Some(ref salt)) = (&self.secret_hash, &self.salt) {
109            verify_api_key(provided_key, hash, salt)
110        } else {
111            // Fallback to plain text comparison for legacy keys
112            Ok(provided_key == self.key)
113        }
114    }
115
116    /// Convert to secure storage format (without plain text key)
117    pub fn to_secure_storage(&self) -> SecureApiKey {
118        SecureApiKey {
119            id: self.id.clone(),
120            name: self.name.clone(),
121            secret_hash: self.secret_hash.clone(),
122            salt: self.salt.clone(),
123            role: self.role.clone(),
124            created_at: self.created_at,
125            expires_at: self.expires_at,
126            last_used: self.last_used,
127            ip_whitelist: self.ip_whitelist.clone(),
128            active: self.active,
129            usage_count: self.usage_count,
130        }
131    }
132}
133
134/// Secure API key for storage (without plain text key)
135#[derive(Debug, Clone, Serialize, Deserialize)]
136pub struct SecureApiKey {
137    /// Unique key identifier (format: lmcp_{role}_{timestamp}_{random})
138    pub id: String,
139    /// Human-readable name/description
140    pub name: String,
141    /// Secure hash of the secret token (for storage)
142    pub secret_hash: Option<String>,
143    /// Salt used for hashing the secret token
144    pub salt: Option<Salt>,
145    /// Role-based permissions
146    pub role: Role,
147    /// Creation timestamp
148    pub created_at: DateTime<Utc>,
149    /// Optional expiration timestamp
150    pub expires_at: Option<DateTime<Utc>>,
151    /// Last time this key was used
152    pub last_used: Option<DateTime<Utc>>,
153    /// IP address whitelist (empty = all IPs allowed)
154    #[serde(default)]
155    pub ip_whitelist: Vec<String>,
156    /// Is the key currently active
157    pub active: bool,
158    /// Usage count
159    #[serde(default)]
160    pub usage_count: u64,
161}
162
163impl SecureApiKey {
164    /// Convert back to ApiKey (without plain text key)
165    pub fn to_api_key(&self) -> ApiKey {
166        ApiKey {
167            id: self.id.clone(),
168            name: self.name.clone(),
169            key: "***redacted***".to_string(), // Never expose plain text
170            secret_hash: self.secret_hash.clone(),
171            salt: self.salt.clone(),
172            role: self.role.clone(),
173            created_at: self.created_at,
174            expires_at: self.expires_at,
175            last_used: self.last_used,
176            ip_whitelist: self.ip_whitelist.clone(),
177            active: self.active,
178            usage_count: self.usage_count,
179        }
180    }
181
182    /// Check if the key is expired
183    pub fn is_expired(&self) -> bool {
184        if let Some(expires_at) = self.expires_at {
185            Utc::now() > expires_at
186        } else {
187            false
188        }
189    }
190
191    /// Check if the key is valid for use
192    pub fn is_valid(&self) -> bool {
193        self.active && !self.is_expired()
194    }
195
196    /// Verify if the provided key matches the stored hash
197    pub fn verify_key(
198        &self,
199        provided_key: &str,
200    ) -> Result<bool, crate::crypto::hashing::HashingError> {
201        use crate::crypto::hashing::verify_api_key;
202
203        if let (Some(ref hash), Some(ref salt)) = (&self.secret_hash, &self.salt) {
204            verify_api_key(provided_key, hash, salt)
205        } else {
206            // Can't verify without hash - this should not happen in production
207            Ok(false)
208        }
209    }
210}
211
212/// User roles with granular permissions
213#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
214#[serde(rename_all = "lowercase")]
215pub enum Role {
216    /// Full system access - all operations including user management
217    Admin,
218    /// Device control and monitoring - no user/key management
219    Operator,
220    /// Read-only access to all resources and status
221    Monitor,
222    /// Limited access to specific devices only
223    Device {
224        /// List of device UUIDs this key can control
225        allowed_devices: Vec<String>,
226    },
227    /// Custom role with specific permission set
228    Custom {
229        /// List of specific permissions
230        permissions: Vec<String>,
231    },
232}
233
234impl Role {
235    /// Check if this role has a specific permission
236    pub fn has_permission(&self, permission: &str) -> bool {
237        match self {
238            Role::Admin => true,                                 // Admin has all permissions
239            Role::Operator => !permission.starts_with("admin."), // No admin permissions
240            Role::Monitor => permission.starts_with("read.") || permission == "health.check",
241            Role::Device { allowed_devices } => {
242                // Check if permission is for an allowed device
243                if let Some(device_uuid) = permission.strip_prefix("device.") {
244                    allowed_devices.contains(&device_uuid.to_string())
245                } else {
246                    false
247                }
248            }
249            Role::Custom { permissions } => permissions.contains(&permission.to_string()),
250        }
251    }
252
253    /// Get a human-readable description of this role
254    pub fn description(&self) -> String {
255        match self {
256            Role::Admin => "Full administrative access".to_string(),
257            Role::Operator => "Device control and monitoring".to_string(),
258            Role::Monitor => "Read-only system monitoring".to_string(),
259            Role::Device { allowed_devices } => {
260                format!("Device control for {} devices", allowed_devices.len())
261            }
262            Role::Custom { permissions } => {
263                format!("Custom role with {} permissions", permissions.len())
264            }
265        }
266    }
267}
268
269impl fmt::Display for Role {
270    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
271        match self {
272            Role::Admin => write!(f, "admin"),
273            Role::Operator => write!(f, "operator"),
274            Role::Monitor => write!(f, "monitor"),
275            Role::Device { .. } => write!(f, "device"),
276            Role::Custom { .. } => write!(f, "custom"),
277        }
278    }
279}
280
281/// Authentication result
282#[derive(Debug)]
283pub struct AuthResult {
284    pub success: bool,
285    pub user_id: Option<String>,
286    pub roles: Vec<Role>,
287    pub message: Option<String>,
288    /// Rate limiting information
289    pub rate_limited: bool,
290    /// Client IP address
291    pub client_ip: Option<String>,
292}
293
294impl AuthResult {
295    /// Create a successful authentication result
296    pub fn success(user_id: String, roles: Vec<Role>) -> Self {
297        Self {
298            success: true,
299            user_id: Some(user_id),
300            roles,
301            message: None,
302            rate_limited: false,
303            client_ip: None,
304        }
305    }
306
307    /// Create a failed authentication result
308    pub fn failure(message: String) -> Self {
309        Self {
310            success: false,
311            user_id: None,
312            roles: vec![],
313            message: Some(message),
314            rate_limited: false,
315            client_ip: None,
316        }
317    }
318
319    /// Create a rate limited authentication result
320    pub fn rate_limited(client_ip: String) -> Self {
321        Self {
322            success: false,
323            user_id: None,
324            roles: vec![],
325            message: Some("Too many failed attempts".to_string()),
326            rate_limited: true,
327            client_ip: Some(client_ip),
328        }
329    }
330}
331
332/// Authentication context
333#[derive(Debug, Clone, Serialize, Deserialize)]
334pub struct AuthContext {
335    pub user_id: Option<String>,
336    pub roles: Vec<Role>,
337    pub api_key_id: Option<String>,
338    /// Permissions derived from roles
339    pub permissions: Vec<String>,
340}
341
342impl AuthContext {
343    /// Check if this context has a specific permission
344    pub fn has_permission(&self, permission: &str) -> bool {
345        self.roles
346            .iter()
347            .any(|role| role.has_permission(permission))
348    }
349
350    /// Get all permissions for this context
351    pub fn get_all_permissions(&self) -> Vec<String> {
352        self.permissions.clone()
353    }
354}
355
356/// Request for creating an API key
357#[derive(Debug, Clone, Serialize, Deserialize)]
358pub struct KeyCreationRequest {
359    /// Human-readable name for the key
360    pub name: String,
361    /// Role to assign to the key
362    pub role: Role,
363    /// Optional expiration date
364    pub expires_at: Option<DateTime<Utc>>,
365    /// Optional IP whitelist
366    pub ip_whitelist: Option<Vec<String>>,
367}
368
369/// API key usage statistics
370#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize)]
371pub struct KeyUsageStats {
372    /// Total number of keys
373    pub total_keys: u32,
374    /// Number of active keys
375    pub active_keys: u32,
376    /// Number of disabled keys
377    pub disabled_keys: u32,
378    /// Number of expired keys
379    pub expired_keys: u32,
380    /// Total usage count across all keys
381    pub total_usage_count: u64,
382    /// Admin role keys
383    pub admin_keys: u32,
384    /// Operator role keys
385    pub operator_keys: u32,
386    /// Monitor role keys
387    pub monitor_keys: u32,
388    /// Device role keys
389    pub device_keys: u32,
390    /// Custom role keys
391    pub custom_keys: u32,
392}
393
394/// API completeness check result
395#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
396pub struct ApiCompletenessCheck {
397    /// Has create_key method
398    pub has_create_key: bool,
399    /// Has validate_key method
400    pub has_validate_key: bool,
401    /// Has list_keys method
402    pub has_list_keys: bool,
403    /// Has revoke_key method
404    pub has_revoke_key: bool,
405    /// Has update_key method
406    pub has_update_key: bool,
407    /// Has bulk operations
408    pub has_bulk_operations: bool,
409    /// Has role-based access control
410    pub has_role_based_access: bool,
411    /// Has rate limiting
412    pub has_rate_limiting: bool,
413    /// Has IP whitelisting
414    pub has_ip_whitelisting: bool,
415    /// Has expiration support
416    pub has_expiration_support: bool,
417    /// Has usage tracking
418    pub has_usage_tracking: bool,
419    /// Framework version
420    pub framework_version: String,
421    /// Is production ready
422    pub production_ready: bool,
423}
424
425#[cfg(test)]
426mod tests {
427    use super::*;
428    use chrono::{Duration, Utc};
429
430    #[test]
431    fn test_api_key_creation() {
432        let key = ApiKey::new(
433            "test-key".to_string(),
434            Role::Operator,
435            Some(Utc::now() + Duration::days(30)),
436            vec!["192.168.1.1".to_string()],
437        );
438
439        assert!(!key.id.is_empty());
440        assert_eq!(key.name, "test-key");
441        assert!(!key.key.is_empty());
442        assert!(key.secret_hash.is_some());
443        assert!(key.salt.is_some());
444        assert_eq!(key.role, Role::Operator);
445        assert!(key.expires_at.is_some());
446        assert!(key.last_used.is_none());
447        assert_eq!(key.ip_whitelist, vec!["192.168.1.1"]);
448        assert!(key.active);
449        assert_eq!(key.usage_count, 0);
450    }
451
452    #[test]
453    fn test_api_key_creation_different_roles() {
454        let admin_key = ApiKey::new("admin".to_string(), Role::Admin, None, vec![]);
455        let monitor_key = ApiKey::new("monitor".to_string(), Role::Monitor, None, vec![]);
456        let device_key = ApiKey::new(
457            "device".to_string(),
458            Role::Device {
459                allowed_devices: vec!["device1".to_string()],
460            },
461            None,
462            vec![],
463        );
464
465        assert_eq!(admin_key.role, Role::Admin);
466        assert_eq!(monitor_key.role, Role::Monitor);
467        assert!(matches!(device_key.role, Role::Device { .. }));
468    }
469
470    #[test]
471    fn test_api_key_id_format() {
472        let admin_key = ApiKey::new("admin".to_string(), Role::Admin, None, vec![]);
473        let operator_key = ApiKey::new("operator".to_string(), Role::Operator, None, vec![]);
474        let monitor_key = ApiKey::new("monitor".to_string(), Role::Monitor, None, vec![]);
475        let device_key = ApiKey::new(
476            "device".to_string(),
477            Role::Device {
478                allowed_devices: vec![],
479            },
480            None,
481            vec![],
482        );
483        let custom_key = ApiKey::new(
484            "custom".to_string(),
485            Role::Custom {
486                permissions: vec!["test:read".to_string()],
487            },
488            None,
489            vec![],
490        );
491
492        assert!(admin_key.id.contains("admin"));
493        assert!(operator_key.id.contains("op"));
494        assert!(monitor_key.id.contains("mon"));
495        assert!(device_key.id.contains("dev"));
496        assert!(custom_key.id.contains("custom"));
497    }
498
499    #[test]
500    fn test_api_key_expiration() {
501        let expired_key = ApiKey::new(
502            "expired".to_string(),
503            Role::Monitor,
504            Some(Utc::now() - Duration::days(1)),
505            vec![],
506        );
507        let valid_key = ApiKey::new(
508            "valid".to_string(),
509            Role::Monitor,
510            Some(Utc::now() + Duration::days(1)),
511            vec![],
512        );
513        let no_expiry_key = ApiKey::new("no-expiry".to_string(), Role::Monitor, None, vec![]);
514
515        assert!(expired_key.is_expired());
516        assert!(!valid_key.is_expired());
517        assert!(!no_expiry_key.is_expired());
518    }
519
520    #[test]
521    fn test_api_key_validity() {
522        let valid_key = ApiKey::new(
523            "valid".to_string(),
524            Role::Monitor,
525            Some(Utc::now() + Duration::days(1)),
526            vec![],
527        );
528        let expired_key = ApiKey::new(
529            "expired".to_string(),
530            Role::Monitor,
531            Some(Utc::now() - Duration::days(1)),
532            vec![],
533        );
534        let mut inactive_key = ApiKey::new("inactive".to_string(), Role::Monitor, None, vec![]);
535        inactive_key.active = false;
536
537        assert!(valid_key.is_valid());
538        assert!(!expired_key.is_valid());
539        assert!(!inactive_key.is_valid());
540    }
541
542    #[test]
543    fn test_api_key_mark_used() {
544        let mut key = ApiKey::new("test".to_string(), Role::Monitor, None, vec![]);
545        assert!(key.last_used.is_none());
546        assert_eq!(key.usage_count, 0);
547
548        key.mark_used();
549        assert!(key.last_used.is_some());
550        assert_eq!(key.usage_count, 1);
551
552        key.mark_used();
553        assert_eq!(key.usage_count, 2);
554    }
555
556    #[test]
557    fn test_api_key_verification() {
558        let key = ApiKey::new("test".to_string(), Role::Monitor, None, vec![]);
559        let correct_secret = key.key.clone();
560        let wrong_secret = "wrong-secret";
561
562        let result_correct = key.verify_key(&correct_secret);
563        let result_wrong = key.verify_key(wrong_secret);
564
565        assert!(result_correct.is_ok());
566        assert!(result_correct.unwrap());
567        assert!(result_wrong.is_ok());
568        assert!(!result_wrong.unwrap());
569    }
570
571    #[test]
572    fn test_api_key_to_secure_storage() {
573        let key = ApiKey::new("test".to_string(), Role::Admin, None, vec![]);
574        let secure_key = key.to_secure_storage();
575
576        assert_eq!(secure_key.id, key.id);
577        assert_eq!(secure_key.name, key.name);
578        assert_eq!(secure_key.secret_hash, key.secret_hash);
579        assert_eq!(secure_key.salt, key.salt);
580        assert_eq!(secure_key.role, key.role);
581        assert_eq!(secure_key.created_at, key.created_at);
582        assert_eq!(secure_key.expires_at, key.expires_at);
583        assert_eq!(secure_key.last_used, key.last_used);
584        assert_eq!(secure_key.ip_whitelist, key.ip_whitelist);
585        assert_eq!(secure_key.active, key.active);
586        assert_eq!(secure_key.usage_count, key.usage_count);
587    }
588
589    #[test]
590    fn test_secure_api_key_to_api_key() {
591        let original_key = ApiKey::new("test".to_string(), Role::Admin, None, vec![]);
592        let secure_key = original_key.to_secure_storage();
593        let restored_key = secure_key.to_api_key();
594
595        assert_eq!(restored_key.id, original_key.id);
596        assert_eq!(restored_key.name, original_key.name);
597        assert_eq!(restored_key.key, "***redacted***"); // Key should be redacted
598        assert_eq!(restored_key.secret_hash, original_key.secret_hash);
599        assert_eq!(restored_key.salt, original_key.salt);
600        assert_eq!(restored_key.role, original_key.role);
601    }
602
603    #[test]
604    fn test_secure_api_key_expiration() {
605        let expired_key = ApiKey::new(
606            "expired".to_string(),
607            Role::Monitor,
608            Some(Utc::now() - Duration::days(1)),
609            vec![],
610        );
611        let secure_expired = expired_key.to_secure_storage();
612
613        assert!(secure_expired.is_expired());
614        assert!(!secure_expired.is_valid());
615    }
616
617    #[test]
618    fn test_secure_api_key_verification() {
619        let key = ApiKey::new("test".to_string(), Role::Monitor, None, vec![]);
620        let secret = key.key.clone();
621        let secure_key = key.to_secure_storage();
622
623        let result = secure_key.verify_key(&secret);
624        assert!(result.is_ok());
625        assert!(result.unwrap());
626
627        let wrong_result = secure_key.verify_key("wrong");
628        assert!(wrong_result.is_ok());
629        assert!(!wrong_result.unwrap());
630    }
631
632    #[test]
633    fn test_role_admin_permissions() {
634        let admin_role = Role::Admin;
635
636        assert!(admin_role.has_permission("admin.create_user"));
637        assert!(admin_role.has_permission("read.status"));
638        assert!(admin_role.has_permission("device.control"));
639        assert!(admin_role.has_permission("anything.really"));
640    }
641
642    #[test]
643    fn test_role_operator_permissions() {
644        let operator_role = Role::Operator;
645
646        assert!(operator_role.has_permission("read.status"));
647        assert!(operator_role.has_permission("device.control"));
648        assert!(!operator_role.has_permission("admin.create_user"));
649        assert!(!operator_role.has_permission("admin.delete_key"));
650    }
651
652    #[test]
653    fn test_role_monitor_permissions() {
654        let monitor_role = Role::Monitor;
655
656        assert!(monitor_role.has_permission("read.status"));
657        assert!(monitor_role.has_permission("read.metrics"));
658        assert!(monitor_role.has_permission("health.check"));
659        assert!(!monitor_role.has_permission("write.config"));
660        assert!(!monitor_role.has_permission("device.control"));
661        assert!(!monitor_role.has_permission("admin.anything"));
662    }
663
664    #[test]
665    fn test_role_device_permissions() {
666        let allowed_devices = vec!["device1".to_string(), "device2".to_string()];
667        let device_role = Role::Device {
668            allowed_devices: allowed_devices.clone(),
669        };
670
671        assert!(device_role.has_permission("device.device1"));
672        assert!(device_role.has_permission("device.device2"));
673        assert!(!device_role.has_permission("device.device3"));
674        assert!(!device_role.has_permission("read.status"));
675        assert!(!device_role.has_permission("admin.anything"));
676    }
677
678    #[test]
679    fn test_role_custom_permissions() {
680        let permissions = vec![
681            "custom.read".to_string(),
682            "custom.write".to_string(),
683            "special.action".to_string(),
684        ];
685        let custom_role = Role::Custom {
686            permissions: permissions.clone(),
687        };
688
689        assert!(custom_role.has_permission("custom.read"));
690        assert!(custom_role.has_permission("custom.write"));
691        assert!(custom_role.has_permission("special.action"));
692        assert!(!custom_role.has_permission("custom.delete"));
693        assert!(!custom_role.has_permission("admin.anything"));
694    }
695
696    #[test]
697    fn test_role_descriptions() {
698        let admin = Role::Admin;
699        let operator = Role::Operator;
700        let monitor = Role::Monitor;
701        let device = Role::Device {
702            allowed_devices: vec!["dev1".to_string(), "dev2".to_string()],
703        };
704        let custom = Role::Custom {
705            permissions: vec![
706                "perm1".to_string(),
707                "perm2".to_string(),
708                "perm3".to_string(),
709            ],
710        };
711
712        assert_eq!(admin.description(), "Full administrative access");
713        assert_eq!(operator.description(), "Device control and monitoring");
714        assert_eq!(monitor.description(), "Read-only system monitoring");
715        assert_eq!(device.description(), "Device control for 2 devices");
716        assert_eq!(custom.description(), "Custom role with 3 permissions");
717    }
718
719    #[test]
720    fn test_role_display() {
721        assert_eq!(Role::Admin.to_string(), "admin");
722        assert_eq!(Role::Operator.to_string(), "operator");
723        assert_eq!(Role::Monitor.to_string(), "monitor");
724        assert_eq!(
725            Role::Device {
726                allowed_devices: vec![]
727            }
728            .to_string(),
729            "device"
730        );
731        assert_eq!(
732            Role::Custom {
733                permissions: vec![]
734            }
735            .to_string(),
736            "custom"
737        );
738    }
739
740    #[test]
741    fn test_auth_result_success() {
742        let result = AuthResult::success("user123".to_string(), vec![Role::Admin]);
743
744        assert!(result.success);
745        assert_eq!(result.user_id, Some("user123".to_string()));
746        assert_eq!(result.roles, vec![Role::Admin]);
747        assert!(result.message.is_none());
748        assert!(!result.rate_limited);
749        assert!(result.client_ip.is_none());
750    }
751
752    #[test]
753    fn test_auth_result_failure() {
754        let result = AuthResult::failure("Invalid credentials".to_string());
755
756        assert!(!result.success);
757        assert!(result.user_id.is_none());
758        assert!(result.roles.is_empty());
759        assert_eq!(result.message, Some("Invalid credentials".to_string()));
760        assert!(!result.rate_limited);
761        assert!(result.client_ip.is_none());
762    }
763
764    #[test]
765    fn test_auth_result_rate_limited() {
766        let result = AuthResult::rate_limited("192.168.1.100".to_string());
767
768        assert!(!result.success);
769        assert!(result.user_id.is_none());
770        assert!(result.roles.is_empty());
771        assert_eq!(result.message, Some("Too many failed attempts".to_string()));
772        assert!(result.rate_limited);
773        assert_eq!(result.client_ip, Some("192.168.1.100".to_string()));
774    }
775
776    #[test]
777    fn test_auth_context_permissions() {
778        let context = AuthContext {
779            user_id: Some("user123".to_string()),
780            roles: vec![Role::Admin, Role::Operator],
781            api_key_id: Some("key456".to_string()),
782            permissions: vec![
783                "admin.create".to_string(),
784                "read.status".to_string(),
785                "device.control".to_string(),
786            ],
787        };
788
789        assert!(context.has_permission("admin.create"));
790        assert!(context.has_permission("read.status"));
791        assert!(context.has_permission("anything")); // Admin role allows all
792
793        let permissions = context.get_all_permissions();
794        assert_eq!(permissions.len(), 3);
795        assert!(permissions.contains(&"admin.create".to_string()));
796    }
797
798    #[test]
799    fn test_auth_context_mixed_roles() {
800        let context = AuthContext {
801            user_id: Some("user123".to_string()),
802            roles: vec![
803                Role::Monitor,
804                Role::Device {
805                    allowed_devices: vec!["device1".to_string()],
806                },
807            ],
808            api_key_id: Some("key456".to_string()),
809            permissions: vec!["read.status".to_string(), "device.device1".to_string()],
810        };
811
812        assert!(context.has_permission("read.status")); // Monitor role
813        assert!(context.has_permission("device.device1")); // Device role
814        assert!(!context.has_permission("device.device2")); // Not allowed device
815        assert!(!context.has_permission("admin.create")); // No admin permissions
816    }
817
818    #[test]
819    fn test_key_creation_request_serialization() {
820        let request = KeyCreationRequest {
821            name: "test-key".to_string(),
822            role: Role::Operator,
823            expires_at: Some(Utc::now() + Duration::days(30)),
824            ip_whitelist: Some(vec!["192.168.1.1".to_string()]),
825        };
826
827        let json = serde_json::to_string(&request).unwrap();
828        let deserialized: KeyCreationRequest = serde_json::from_str(&json).unwrap();
829
830        assert_eq!(deserialized.name, request.name);
831        assert_eq!(deserialized.role, request.role);
832        assert_eq!(deserialized.expires_at, request.expires_at);
833        assert_eq!(deserialized.ip_whitelist, request.ip_whitelist);
834    }
835
836    #[test]
837    fn test_key_usage_stats_default() {
838        let stats = KeyUsageStats::default();
839
840        assert_eq!(stats.total_keys, 0);
841        assert_eq!(stats.active_keys, 0);
842        assert_eq!(stats.disabled_keys, 0);
843        assert_eq!(stats.expired_keys, 0);
844        assert_eq!(stats.total_usage_count, 0);
845        assert_eq!(stats.admin_keys, 0);
846        assert_eq!(stats.operator_keys, 0);
847        assert_eq!(stats.monitor_keys, 0);
848        assert_eq!(stats.device_keys, 0);
849        assert_eq!(stats.custom_keys, 0);
850    }
851
852    #[test]
853    fn test_api_completeness_check_serialization() {
854        let check = ApiCompletenessCheck {
855            has_create_key: true,
856            has_validate_key: true,
857            has_list_keys: true,
858            has_revoke_key: true,
859            has_update_key: false,
860            has_bulk_operations: false,
861            has_role_based_access: true,
862            has_rate_limiting: true,
863            has_ip_whitelisting: true,
864            has_expiration_support: true,
865            has_usage_tracking: true,
866            framework_version: "1.0.0".to_string(),
867            production_ready: true,
868        };
869
870        let json = serde_json::to_string(&check).unwrap();
871        let deserialized: ApiCompletenessCheck = serde_json::from_str(&json).unwrap();
872
873        assert_eq!(deserialized.has_create_key, check.has_create_key);
874        assert_eq!(deserialized.framework_version, check.framework_version);
875        assert_eq!(deserialized.production_ready, check.production_ready);
876    }
877
878    #[test]
879    fn test_role_equality() {
880        let admin1 = Role::Admin;
881        let admin2 = Role::Admin;
882        let operator = Role::Operator;
883
884        assert_eq!(admin1, admin2);
885        assert_ne!(admin1, operator);
886
887        let device1 = Role::Device {
888            allowed_devices: vec!["dev1".to_string()],
889        };
890        let device2 = Role::Device {
891            allowed_devices: vec!["dev1".to_string()],
892        };
893        let device3 = Role::Device {
894            allowed_devices: vec!["dev2".to_string()],
895        };
896
897        assert_eq!(device1, device2);
898        assert_ne!(device1, device3);
899    }
900
901    #[test]
902    fn test_api_key_serialization() {
903        let key = ApiKey::new("test".to_string(), Role::Admin, None, vec![]);
904
905        let json = serde_json::to_string(&key).unwrap();
906        let deserialized: ApiKey = serde_json::from_str(&json).unwrap();
907
908        assert_eq!(deserialized.id, key.id);
909        assert_eq!(deserialized.name, key.name);
910        assert_eq!(deserialized.role, key.role);
911        assert_eq!(deserialized.active, key.active);
912        assert_eq!(deserialized.usage_count, key.usage_count);
913    }
914}