qorzen_oxide/auth/
mod.rs

1// src/auth/mod.rs - Authentication and authorization system
2
3use std::collections::HashMap;
4use std::sync::Arc;
5
6use crate::utils::Time;
7use async_trait::async_trait;
8use chrono::{DateTime, Utc};
9use serde::{Deserialize, Serialize};
10use tokio::sync::RwLock;
11use uuid::Uuid;
12
13use crate::error::{Error, Result};
14use crate::manager::{ManagedState, Manager, ManagerStatus, PlatformRequirements};
15
16pub type UserId = Uuid;
17
18#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
19pub struct User {
20    pub id: UserId,
21    pub username: String,
22    pub email: String,
23    pub roles: Vec<Role>,
24    pub permissions: Vec<Permission>,
25    pub preferences: UserPreferences,
26    pub profile: UserProfile,
27    pub created_at: DateTime<Utc>,
28    pub last_login: Option<DateTime<Utc>>,
29    pub is_active: bool,
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
33pub struct Role {
34    pub id: String,
35    pub name: String,
36    pub description: String,
37    pub permissions: Vec<Permission>,
38    pub ui_layout: Option<String>,
39    pub is_system_role: bool,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
43pub struct Permission {
44    pub resource: String, // "user.profile", "plugin.inventory", "system.config"
45    pub action: String,   // "read", "write", "delete", "execute"
46    pub scope: PermissionScope,
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
50pub enum PermissionScope {
51    Own,                // User's own resources
52    Department(String), // Department-specific resources
53    Global,             // All resources
54}
55
56#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
57pub struct UserPreferences {
58    pub theme: String,
59    pub language: String,
60    pub timezone: String,
61    pub notifications_enabled: bool,
62    pub custom_settings: HashMap<String, serde_json::Value>,
63}
64
65impl Default for UserPreferences {
66    fn default() -> Self {
67        Self {
68            theme: "default".to_string(),
69            language: "en".to_string(),
70            timezone: "UTC".to_string(),
71            notifications_enabled: true,
72            custom_settings: HashMap::new(),
73        }
74    }
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
78pub struct UserProfile {
79    pub display_name: String,
80    pub avatar_url: Option<String>,
81    pub bio: Option<String>,
82    pub department: Option<String>,
83    pub title: Option<String>,
84    pub contact_info: ContactInfo,
85}
86
87#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
88pub struct ContactInfo {
89    pub phone: Option<String>,
90    pub address: Option<String>,
91    pub emergency_contact: Option<String>,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct UserSession {
96    pub id: Uuid,
97    pub user_id: UserId,
98    pub created_at: DateTime<Utc>,
99    pub expires_at: DateTime<Utc>,
100    pub last_activity: DateTime<Utc>,
101    pub ip_address: Option<String>,
102    pub user_agent: Option<String>,
103    pub is_active: bool,
104}
105
106#[derive(Debug, Clone, Serialize, Deserialize)]
107pub enum Credentials {
108    Password {
109        username: String,
110        password: String,
111    },
112    Token {
113        token: String,
114    },
115    OAuth2 {
116        provider: String,
117        code: String,
118        state: Option<String>,
119    },
120    Biometric {
121        user_id: UserId,
122        biometric_data: Vec<u8>,
123    },
124}
125
126#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct AuthResult {
128    pub user: User,
129    pub session: UserSession,
130    pub tokens: TokenPair,
131    pub requires_mfa: bool,
132}
133
134#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct TokenPair {
136    pub access_token: String,
137    pub refresh_token: String,
138    pub token_type: String,
139    pub expires_in: u64,
140}
141
142#[derive(Debug, Clone, Serialize, Deserialize)]
143pub struct Claims {
144    pub sub: String, // user ID
145    pub iat: i64,    // issued at
146    pub exp: i64,    // expires at
147    pub aud: String, // audience
148    pub iss: String, // issuer
149    pub roles: Vec<String>,
150    pub permissions: Vec<String>,
151}
152
153#[derive(Debug, Clone, Serialize, Deserialize)]
154pub enum AuthProviderType {
155    Local,
156    OAuth2 { provider: String },
157    SAML { provider: String },
158    LDAP { server: String },
159}
160
161#[cfg(not(target_arch = "wasm32"))]
162#[async_trait]
163pub trait AuthProvider: Send + Sync {
164    async fn authenticate(&self, credentials: &Credentials) -> Result<AuthResult>;
165    async fn refresh_token(&self, refresh_token: &str) -> Result<TokenPair>;
166    async fn validate_token(&self, token: &str) -> Result<Claims>;
167    fn provider_type(&self) -> AuthProviderType;
168}
169
170#[cfg(target_arch = "wasm32")]
171#[async_trait(?Send)]
172pub trait AuthProvider: Sync {
173    async fn authenticate(&self, credentials: &Credentials) -> Result<AuthResult>;
174    async fn refresh_token(&self, refresh_token: &str) -> Result<TokenPair>;
175    async fn validate_token(&self, token: &str) -> Result<Claims>;
176    fn provider_type(&self) -> AuthProviderType;
177}
178
179#[cfg(not(target_arch = "wasm32"))]
180#[async_trait]
181pub trait SessionStore: Send + Sync {
182    async fn create_session(&self, session: UserSession) -> Result<()>;
183    async fn get_session(&self, session_id: Uuid) -> Result<Option<UserSession>>;
184    async fn update_session(&self, session: UserSession) -> Result<()>;
185    async fn delete_session(&self, session_id: Uuid) -> Result<()>;
186    async fn cleanup_expired_sessions(&self) -> Result<u64>;
187}
188
189#[cfg(target_arch = "wasm32")]
190#[async_trait(?Send)]
191pub trait SessionStore: Sync {
192    async fn create_session(&self, session: UserSession) -> Result<()>;
193    async fn get_session(&self, session_id: Uuid) -> Result<Option<UserSession>>;
194    async fn update_session(&self, session: UserSession) -> Result<()>;
195    async fn delete_session(&self, session_id: Uuid) -> Result<()>;
196    async fn cleanup_expired_sessions(&self) -> Result<u64>;
197}
198
199#[cfg(not(target_arch = "wasm32"))]
200#[async_trait]
201pub trait UserStore: Send + Sync {
202    async fn create_user(&self, user: User) -> Result<()>;
203    async fn get_user(&self, user_id: UserId) -> Result<Option<User>>;
204    async fn get_user_by_username(&self, username: &str) -> Result<Option<User>>;
205    async fn get_user_by_email(&self, email: &str) -> Result<Option<User>>;
206    async fn update_user(&self, user: User) -> Result<()>;
207    async fn delete_user(&self, user_id: UserId) -> Result<()>;
208    async fn list_users(&self, limit: Option<u32>, offset: Option<u32>) -> Result<Vec<User>>;
209}
210
211#[cfg(target_arch = "wasm32")]
212#[async_trait(?Send)]
213pub trait UserStore: Sync {
214    async fn create_user(&self, user: User) -> Result<()>;
215    async fn get_user(&self, user_id: UserId) -> Result<Option<User>>;
216    async fn get_user_by_username(&self, username: &str) -> Result<Option<User>>;
217    async fn get_user_by_email(&self, email: &str) -> Result<Option<User>>;
218    async fn update_user(&self, user: User) -> Result<()>;
219    async fn delete_user(&self, user_id: UserId) -> Result<()>;
220    async fn list_users(&self, limit: Option<u32>, offset: Option<u32>) -> Result<Vec<User>>;
221}
222
223pub struct PermissionCache {
224    cache: HashMap<(UserId, String, String), bool>,
225    last_updated: DateTime<Utc>,
226}
227
228impl PermissionCache {
229    fn new() -> Self {
230        Self {
231            cache: HashMap::new(),
232            last_updated: Time::now(),
233        }
234    }
235
236    fn check_permission(&self, user_id: UserId, resource: &str, action: &str) -> Option<bool> {
237        self.cache
238            .get(&(user_id, resource.to_string(), action.to_string()))
239            .copied()
240    }
241
242    fn cache_permission(&mut self, user_id: UserId, resource: &str, action: &str, allowed: bool) {
243        self.cache
244            .insert((user_id, resource.to_string(), action.to_string()), allowed);
245        self.last_updated = Time::now();
246    }
247
248    fn clear_user_cache(&mut self, user_id: UserId) {
249        self.cache.retain(|(id, _, _), _value| *id != user_id);
250        self.last_updated = Time::now();
251    }
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize)]
255pub struct SecurityPolicy {
256    pub password_min_length: u32,
257    pub password_require_uppercase: bool,
258    pub password_require_lowercase: bool,
259    pub password_require_numbers: bool,
260    pub password_require_symbols: bool,
261    pub session_timeout_minutes: u64,
262    pub max_login_attempts: u32,
263    pub lockout_duration_minutes: u64,
264    pub require_mfa: bool,
265    pub allowed_login_methods: Vec<AuthProviderType>,
266}
267
268impl Default for SecurityPolicy {
269    fn default() -> Self {
270        Self {
271            password_min_length: 8,
272            password_require_uppercase: true,
273            password_require_lowercase: true,
274            password_require_numbers: true,
275            password_require_symbols: false,
276            session_timeout_minutes: 480, // 8 hours
277            max_login_attempts: 5,
278            lockout_duration_minutes: 30,
279            require_mfa: false,
280            allowed_login_methods: vec![AuthProviderType::Local],
281        }
282    }
283}
284
285pub struct AccountManager {
286    state: ManagedState,
287    auth_providers: HashMap<String, Box<dyn AuthProvider>>,
288    session_store: Box<dyn SessionStore>,
289    permission_cache: Arc<RwLock<PermissionCache>>,
290    user_store: Box<dyn UserStore>,
291    security_policy: SecurityPolicy,
292    current_user: Arc<RwLock<Option<User>>>,
293    current_session: Arc<RwLock<Option<UserSession>>>,
294}
295
296impl std::fmt::Debug for AccountManager {
297    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
298        f.debug_struct("AccountManager")
299            .field("security_policy", &self.security_policy)
300            .finish()
301    }
302}
303
304impl AccountManager {
305    pub fn new(
306        session_store: Box<dyn SessionStore>,
307        user_store: Box<dyn UserStore>,
308        security_policy: SecurityPolicy,
309    ) -> Self {
310        Self {
311            state: ManagedState::new(Uuid::new_v4(), "account_manager"),
312            auth_providers: HashMap::new(),
313            session_store,
314            permission_cache: Arc::new(RwLock::new(PermissionCache::new())),
315            user_store,
316            security_policy,
317            current_user: Arc::new(RwLock::new(None)),
318            current_session: Arc::new(RwLock::new(None)),
319        }
320    }
321
322    pub fn register_auth_provider(&mut self, name: String, provider: Box<dyn AuthProvider>) {
323        self.auth_providers.insert(name, provider);
324    }
325
326    pub async fn authenticate(
327        &self,
328        credentials: Credentials,
329        provider: Option<&str>,
330    ) -> Result<AuthResult> {
331        let provider_name = provider.unwrap_or("local");
332        let auth_provider = self.auth_providers.get(provider_name).ok_or_else(|| {
333            Error::authentication(format!(
334                "Authentication provider '{}' not found",
335                provider_name
336            ))
337        })?;
338
339        let auth_result = auth_provider.authenticate(&credentials).await?;
340
341        // Store session
342        self.session_store
343            .create_session(auth_result.session.clone())
344            .await?;
345
346        // Update current user and session
347        *self.current_user.write().await = Some(auth_result.user.clone());
348        *self.current_session.write().await = Some(auth_result.session.clone());
349
350        // Clear permission cache for user
351        self.permission_cache
352            .write()
353            .await
354            .clear_user_cache(auth_result.user.id);
355
356        Ok(auth_result)
357    }
358
359    pub async fn validate_token(&self, token: &str, provider: Option<&str>) -> Result<Claims> {
360        let provider_name = provider.unwrap_or("local");
361        let auth_provider = self.auth_providers.get(provider_name).ok_or_else(|| {
362            Error::authentication(format!(
363                "Authentication provider '{}' not found",
364                provider_name
365            ))
366        })?;
367
368        auth_provider.validate_token(token).await
369    }
370
371    pub async fn refresh_token(
372        &self,
373        refresh_token: &str,
374        provider: Option<&str>,
375    ) -> Result<TokenPair> {
376        let provider_name = provider.unwrap_or("local");
377        let auth_provider = self.auth_providers.get(provider_name).ok_or_else(|| {
378            Error::authentication(format!(
379                "Authentication provider '{}' not found",
380                provider_name
381            ))
382        })?;
383
384        auth_provider.refresh_token(refresh_token).await
385    }
386
387    pub async fn logout(&self, session_id: Option<Uuid>) -> Result<()> {
388        if let Some(id) = session_id {
389            self.session_store.delete_session(id).await?;
390        } else if let Some(session) = self.current_session.read().await.as_ref() {
391            self.session_store.delete_session(session.id).await?;
392        }
393
394        // Clear current user and session
395        *self.current_user.write().await = None;
396        *self.current_session.write().await = None;
397
398        Ok(())
399    }
400
401    pub async fn current_user(&self) -> Option<User> {
402        self.current_user.read().await.clone()
403    }
404
405    pub async fn current_session(&self) -> Option<UserSession> {
406        self.current_session.read().await.clone()
407    }
408
409    pub async fn check_permission(
410        &self,
411        user_id: UserId,
412        resource: &str,
413        action: &str,
414    ) -> Result<bool> {
415        // Check cache first
416        if let Some(cached) = self
417            .permission_cache
418            .read()
419            .await
420            .check_permission(user_id, resource, action)
421        {
422            return Ok(cached);
423        }
424
425        // Load user and check permissions
426        let user = self
427            .user_store
428            .get_user(user_id)
429            .await?
430            .ok_or_else(|| Error::authorization(resource, action, "User not found"))?;
431
432        let has_permission = self.user_has_permission(&user, resource, action);
433
434        // Cache the result
435        self.permission_cache.write().await.cache_permission(
436            user_id,
437            resource,
438            action,
439            has_permission,
440        );
441
442        Ok(has_permission)
443    }
444
445    pub async fn check_current_user_permission(
446        &self,
447        resource: &str,
448        action: &str,
449    ) -> Result<bool> {
450        let user = self
451            .current_user()
452            .await
453            .ok_or_else(|| Error::authorization(resource, action, "No authenticated user"))?;
454
455        self.check_permission(user.id, resource, action).await
456    }
457
458    pub async fn create_user(&self, mut user: User) -> Result<()> {
459        // Set creation timestamp
460        user.created_at = Time::now();
461        user.id = Uuid::new_v4();
462
463        // Store user
464        self.user_store.create_user(user).await?;
465
466        Ok(())
467    }
468
469    pub async fn update_user(&self, user: User) -> Result<()> {
470        self.user_store.update_user(user.clone()).await?;
471
472        // Clear permission cache for updated user
473        self.permission_cache
474            .write()
475            .await
476            .clear_user_cache(user.id);
477
478        // Update current user if it's the same
479        if let Some(current) = self.current_user.read().await.as_ref() {
480            if current.id == user.id {
481                *self.current_user.write().await = Some(user);
482            }
483        }
484
485        Ok(())
486    }
487
488    pub async fn get_user(&self, user_id: UserId) -> Result<Option<User>> {
489        self.user_store.get_user(user_id).await
490    }
491
492    pub async fn get_user_by_username(&self, username: &str) -> Result<Option<User>> {
493        self.user_store.get_user_by_username(username).await
494    }
495
496    pub async fn list_users(&self, limit: Option<u32>, offset: Option<u32>) -> Result<Vec<User>> {
497        self.user_store.list_users(limit, offset).await
498    }
499
500    pub async fn cleanup_expired_sessions(&self) -> Result<u64> {
501        self.session_store.cleanup_expired_sessions().await
502    }
503
504    fn user_has_permission(&self, user: &User, resource: &str, action: &str) -> bool {
505        // Check direct permissions
506        for permission in &user.permissions {
507            if self.permission_matches(permission, resource, action) {
508                return true;
509            }
510        }
511
512        // Check role permissions
513        for role in &user.roles {
514            for permission in &role.permissions {
515                if self.permission_matches(permission, resource, action) {
516                    return true;
517                }
518            }
519        }
520
521        false
522    }
523
524    fn permission_matches(&self, permission: &Permission, resource: &str, action: &str) -> bool {
525        // Simple string matching - in practice you'd want more sophisticated matching
526        (permission.resource == resource || permission.resource == "*")
527            && (permission.action == action || permission.action == "*")
528    }
529}
530
531#[cfg(not(target_arch = "wasm32"))]
532#[async_trait]
533impl Manager for AccountManager {
534    fn name(&self) -> &str {
535        "account_manager"
536    }
537
538    fn id(&self) -> Uuid {
539        self.state.id()
540    }
541
542    async fn initialize(&mut self) -> Result<()> {
543        self.state
544            .set_state(crate::manager::ManagerState::Initializing)
545            .await;
546
547        // Initialize default auth providers, create admin user if needed, etc.
548
549        self.state
550            .set_state(crate::manager::ManagerState::Running)
551            .await;
552        Ok(())
553    }
554
555    async fn shutdown(&mut self) -> Result<()> {
556        self.state
557            .set_state(crate::manager::ManagerState::ShuttingDown)
558            .await;
559
560        // Cleanup sessions, etc.
561        let _ = self.cleanup_expired_sessions().await;
562
563        self.state
564            .set_state(crate::manager::ManagerState::Shutdown)
565            .await;
566        Ok(())
567    }
568
569    async fn status(&self) -> ManagerStatus {
570        let mut status = self.state.status().await;
571
572        let current_user_id = self
573            .current_user()
574            .await
575            .map(|u| u.id.to_string())
576            .unwrap_or_else(|| "none".to_string());
577        status.add_metadata("current_user", serde_json::Value::String(current_user_id));
578        status.add_metadata(
579            "auth_providers",
580            serde_json::Value::from(self.auth_providers.len()),
581        );
582        status.add_metadata(
583            "security_policy",
584            serde_json::to_value(&self.security_policy).unwrap_or_default(),
585        );
586
587        status
588    }
589
590    fn required_permissions(&self) -> Vec<String> {
591        vec![
592            "auth.login".to_string(),
593            "auth.logout".to_string(),
594            "auth.manage_users".to_string(),
595        ]
596    }
597
598    fn platform_requirements(&self) -> PlatformRequirements {
599        PlatformRequirements {
600            requires_filesystem: false,
601            requires_network: true,
602            requires_database: true,
603            requires_native_apis: false,
604            minimum_permissions: self.required_permissions(),
605        }
606    }
607}
608
609#[cfg(target_arch = "wasm32")]
610#[async_trait(?Send)]
611impl Manager for AccountManager {
612    fn name(&self) -> &str {
613        "account_manager"
614    }
615
616    fn id(&self) -> Uuid {
617        self.state.id()
618    }
619
620    async fn initialize(&mut self) -> Result<()> {
621        self.state
622            .set_state(crate::manager::ManagerState::Initializing)
623            .await;
624
625        // Initialize default auth providers, create admin user if needed, etc.
626
627        self.state
628            .set_state(crate::manager::ManagerState::Running)
629            .await;
630        Ok(())
631    }
632
633    async fn shutdown(&mut self) -> Result<()> {
634        self.state
635            .set_state(crate::manager::ManagerState::ShuttingDown)
636            .await;
637
638        // Cleanup sessions, etc.
639        let _ = self.cleanup_expired_sessions().await;
640
641        self.state
642            .set_state(crate::manager::ManagerState::Shutdown)
643            .await;
644        Ok(())
645    }
646
647    async fn status(&self) -> ManagerStatus {
648        let mut status = self.state.status().await;
649
650        let current_user_id = self
651            .current_user()
652            .await
653            .map(|u| u.id.to_string())
654            .unwrap_or_else(|| "none".to_string());
655        status.add_metadata("current_user", serde_json::Value::String(current_user_id));
656        status.add_metadata(
657            "auth_providers",
658            serde_json::Value::from(self.auth_providers.len()),
659        );
660        status.add_metadata(
661            "security_policy",
662            serde_json::to_value(&self.security_policy).unwrap_or_default(),
663        );
664
665        status
666    }
667
668    fn required_permissions(&self) -> Vec<String> {
669        vec![
670            "auth.login".to_string(),
671            "auth.logout".to_string(),
672            "auth.manage_users".to_string(),
673        ]
674    }
675
676    fn platform_requirements(&self) -> PlatformRequirements {
677        PlatformRequirements {
678            requires_filesystem: false,
679            requires_network: true,
680            requires_database: true,
681            requires_native_apis: false,
682            minimum_permissions: self.required_permissions(),
683        }
684    }
685}
686
687pub struct MemorySessionStore {
688    sessions: Arc<RwLock<HashMap<Uuid, UserSession>>>,
689}
690
691impl Default for MemorySessionStore {
692    fn default() -> Self {
693        Self::new()
694    }
695}
696
697impl MemorySessionStore {
698    pub fn new() -> Self {
699        Self {
700            sessions: Arc::new(RwLock::new(HashMap::new())),
701        }
702    }
703
704    #[allow(dead_code)]
705    fn default() -> Self {
706        Self::new()
707    }
708}
709
710#[cfg(not(target_arch = "wasm32"))]
711#[async_trait]
712impl SessionStore for MemorySessionStore {
713    async fn create_session(&self, session: UserSession) -> Result<()> {
714        self.sessions.write().await.insert(session.id, session);
715        Ok(())
716    }
717
718    async fn get_session(&self, session_id: Uuid) -> Result<Option<UserSession>> {
719        Ok(self.sessions.read().await.get(&session_id).cloned())
720    }
721
722    async fn update_session(&self, session: UserSession) -> Result<()> {
723        self.sessions.write().await.insert(session.id, session);
724        Ok(())
725    }
726
727    async fn delete_session(&self, session_id: Uuid) -> Result<()> {
728        self.sessions.write().await.remove(&session_id);
729        Ok(())
730    }
731
732    async fn cleanup_expired_sessions(&self) -> Result<u64> {
733        let now = Time::now();
734        let mut sessions = self.sessions.write().await;
735        let original_count = sessions.len();
736
737        sessions.retain(|_, session| session.expires_at > now);
738
739        Ok((original_count - sessions.len()) as u64)
740    }
741}
742
743#[cfg(target_arch = "wasm32")]
744#[async_trait(?Send)]
745impl SessionStore for MemorySessionStore {
746    async fn create_session(&self, session: UserSession) -> Result<()> {
747        self.sessions.write().await.insert(session.id, session);
748        Ok(())
749    }
750
751    async fn get_session(&self, session_id: Uuid) -> Result<Option<UserSession>> {
752        Ok(self.sessions.read().await.get(&session_id).cloned())
753    }
754
755    async fn update_session(&self, session: UserSession) -> Result<()> {
756        self.sessions.write().await.insert(session.id, session);
757        Ok(())
758    }
759
760    async fn delete_session(&self, session_id: Uuid) -> Result<()> {
761        self.sessions.write().await.remove(&session_id);
762        Ok(())
763    }
764
765    async fn cleanup_expired_sessions(&self) -> Result<u64> {
766        let now = Time::now();
767        let mut sessions = self.sessions.write().await;
768        let original_count = sessions.len();
769
770        sessions.retain(|_, session| session.expires_at > now);
771
772        Ok((original_count - sessions.len()) as u64)
773    }
774}
775
776pub struct MemoryUserStore {
777    users: Arc<RwLock<HashMap<UserId, User>>>,
778}
779
780impl Default for MemoryUserStore {
781    fn default() -> Self {
782        Self::new()
783    }
784}
785
786impl MemoryUserStore {
787    pub fn new() -> Self {
788        Self {
789            users: Arc::new(RwLock::new(HashMap::new())),
790        }
791    }
792}
793
794#[cfg(not(target_arch = "wasm32"))]
795#[async_trait]
796impl UserStore for MemoryUserStore {
797    async fn create_user(&self, user: User) -> Result<()> {
798        self.users.write().await.insert(user.id, user);
799        Ok(())
800    }
801
802    async fn get_user(&self, user_id: UserId) -> Result<Option<User>> {
803        Ok(self.users.read().await.get(&user_id).cloned())
804    }
805
806    async fn get_user_by_username(&self, username: &str) -> Result<Option<User>> {
807        Ok(self
808            .users
809            .read()
810            .await
811            .values()
812            .find(|u| u.username == username)
813            .cloned())
814    }
815
816    async fn get_user_by_email(&self, email: &str) -> Result<Option<User>> {
817        Ok(self
818            .users
819            .read()
820            .await
821            .values()
822            .find(|u| u.email == email)
823            .cloned())
824    }
825
826    async fn update_user(&self, user: User) -> Result<()> {
827        self.users.write().await.insert(user.id, user);
828        Ok(())
829    }
830
831    async fn delete_user(&self, user_id: UserId) -> Result<()> {
832        self.users.write().await.remove(&user_id);
833        Ok(())
834    }
835
836    async fn list_users(&self, limit: Option<u32>, offset: Option<u32>) -> Result<Vec<User>> {
837        let users: Vec<User> = self.users.read().await.values().cloned().collect();
838
839        let offset = offset.unwrap_or(0) as usize;
840        let limit = limit.map(|l| l as usize);
841
842        let mut result: Vec<User> = users.into_iter().skip(offset).collect();
843
844        if let Some(limit) = limit {
845            result.truncate(limit);
846        }
847
848        Ok(result)
849    }
850}
851
852#[cfg(target_arch = "wasm32")]
853#[async_trait(?Send)]
854impl UserStore for MemoryUserStore {
855    async fn create_user(&self, user: User) -> Result<()> {
856        self.users.write().await.insert(user.id, user);
857        Ok(())
858    }
859
860    async fn get_user(&self, user_id: UserId) -> Result<Option<User>> {
861        Ok(self.users.read().await.get(&user_id).cloned())
862    }
863
864    async fn get_user_by_username(&self, username: &str) -> Result<Option<User>> {
865        Ok(self
866            .users
867            .read()
868            .await
869            .values()
870            .find(|u| u.username == username)
871            .cloned())
872    }
873
874    async fn get_user_by_email(&self, email: &str) -> Result<Option<User>> {
875        Ok(self
876            .users
877            .read()
878            .await
879            .values()
880            .find(|u| u.email == email)
881            .cloned())
882    }
883
884    async fn update_user(&self, user: User) -> Result<()> {
885        self.users.write().await.insert(user.id, user);
886        Ok(())
887    }
888
889    async fn delete_user(&self, user_id: UserId) -> Result<()> {
890        self.users.write().await.remove(&user_id);
891        Ok(())
892    }
893
894    async fn list_users(&self, limit: Option<u32>, offset: Option<u32>) -> Result<Vec<User>> {
895        let users: Vec<User> = self.users.read().await.values().cloned().collect();
896
897        let offset = offset.unwrap_or(0) as usize;
898        let limit = limit.map(|l| l as usize);
899
900        let mut result: Vec<User> = users.into_iter().skip(offset).collect();
901
902        if let Some(limit) = limit {
903            result.truncate(limit);
904        }
905
906        Ok(result)
907    }
908}
909
910#[cfg(test)]
911mod tests {
912    use super::*;
913
914    #[tokio::test]
915    async fn test_user_creation() {
916        let user_store = Box::new(MemoryUserStore::new());
917        let session_store = Box::new(MemorySessionStore::new());
918        let security_policy = SecurityPolicy::default();
919
920        let mut account_manager = AccountManager::new(session_store, user_store, security_policy);
921        account_manager.initialize().await.unwrap();
922
923        let user = User {
924            id: Uuid::new_v4(),
925            username: "testuser".to_string(),
926            email: "test@example.com".to_string(),
927            roles: vec![],
928            permissions: vec![],
929            preferences: UserPreferences::default(),
930            profile: UserProfile {
931                display_name: "Test User".to_string(),
932                avatar_url: None,
933                bio: None,
934                department: None,
935                title: None,
936                contact_info: ContactInfo {
937                    phone: None,
938                    address: None,
939                    emergency_contact: None,
940                },
941            },
942            created_at: Time::now(),
943            last_login: None,
944            is_active: true,
945        };
946
947        account_manager.create_user(user.clone()).await.unwrap();
948
949        let retrieved_user = account_manager
950            .get_user_by_username("testuser")
951            .await
952            .unwrap();
953        assert!(retrieved_user.is_some());
954        assert_eq!(retrieved_user.unwrap().username, "testuser");
955    }
956
957    #[tokio::test]
958    async fn test_permission_checking() {
959        let user_store = Box::new(MemoryUserStore::new());
960        let session_store = Box::new(MemorySessionStore::new());
961        let security_policy = SecurityPolicy::default();
962
963        let account_manager = AccountManager::new(session_store, user_store, security_policy);
964
965        let permission = Permission {
966            resource: "user.profile".to_string(),
967            action: "read".to_string(),
968            scope: PermissionScope::Own,
969        };
970
971        let user = User {
972            id: Uuid::new_v4(),
973            username: "testuser".to_string(),
974            email: "test@example.com".to_string(),
975            roles: vec![],
976            permissions: vec![permission],
977            preferences: UserPreferences::default(),
978            profile: UserProfile {
979                display_name: "Test User".to_string(),
980                avatar_url: None,
981                bio: None,
982                department: None,
983                title: None,
984                contact_info: ContactInfo {
985                    phone: None,
986                    address: None,
987                    emergency_contact: None,
988                },
989            },
990            created_at: Time::now(),
991            last_login: None,
992            is_active: true,
993        };
994
995        account_manager.create_user(user.clone()).await.unwrap();
996
997        let has_permission = account_manager
998            .check_permission(user.id, "user.profile", "read")
999            .await
1000            .unwrap();
1001        assert!(has_permission);
1002
1003        let no_permission = account_manager
1004            .check_permission(user.id, "admin.users", "write")
1005            .await
1006            .unwrap();
1007        assert!(!no_permission);
1008    }
1009}