1use crate::SyncError;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use tokio::sync::RwLock;
7use chrono::{DateTime, Utc, Duration};
8use sha2::{Sha256, Digest};
9use rand::{Rng, rngs::OsRng};
10use base64::{Engine as _, engine::general_purpose};
11
12#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
14pub enum AuthProvider {
15 Local,
16 OAuth2,
17 JWT,
18 LDAP,
19}
20
21#[derive(Debug, Clone, Serialize, Deserialize)]
23pub struct UserSession {
24 pub user_id: String,
25 pub token: String,
26 pub expires_at: DateTime<Utc>,
27 pub created_at: DateTime<Utc>,
28 pub last_activity: DateTime<Utc>,
29 pub ip_address: Option<String>,
30 pub user_agent: Option<String>,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct User {
36 pub id: String,
37 pub username: String,
38 pub email: String,
39 pub password_hash: String,
40 pub salt: String,
41 pub created_at: DateTime<Utc>,
42 pub last_login: Option<DateTime<Utc>>,
43 pub is_active: bool,
44 pub is_verified: bool,
45 pub mfa_enabled: bool,
46 pub mfa_secret: Option<String>,
47 pub failed_login_attempts: u32,
48 pub locked_until: Option<DateTime<Utc>>,
49}
50
51#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct PasswordResetToken {
54 pub token: String,
55 pub user_id: String,
56 pub expires_at: DateTime<Utc>,
57 pub created_at: DateTime<Utc>,
58 pub used: bool,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct AuthConfig {
64 pub session_timeout: Duration,
65 pub max_failed_attempts: u32,
66 pub lockout_duration: Duration,
67 pub password_min_length: usize,
68 pub require_uppercase: bool,
69 pub require_lowercase: bool,
70 pub require_numbers: bool,
71 pub require_special_chars: bool,
72 pub mfa_required: bool,
73}
74
75impl Default for AuthConfig {
76 fn default() -> Self {
77 Self {
78 session_timeout: Duration::hours(24),
79 max_failed_attempts: 5,
80 lockout_duration: Duration::minutes(30),
81 password_min_length: 8,
82 require_uppercase: true,
83 require_lowercase: true,
84 require_numbers: true,
85 require_special_chars: true,
86 mfa_required: false,
87 }
88 }
89}
90
91pub struct AuthenticationManager {
93 config: AuthConfig,
94 users: RwLock<HashMap<String, User>>,
95 sessions: RwLock<HashMap<String, UserSession>>,
96 reset_tokens: RwLock<HashMap<String, PasswordResetToken>>,
97}
98
99impl AuthenticationManager {
100 pub fn new() -> Self {
102 Self {
103 config: AuthConfig::default(),
104 users: RwLock::new(HashMap::new()),
105 sessions: RwLock::new(HashMap::new()),
106 reset_tokens: RwLock::new(HashMap::new()),
107 }
108 }
109
110 pub fn with_config(config: AuthConfig) -> Self {
112 Self {
113 config,
114 users: RwLock::new(HashMap::new()),
115 sessions: RwLock::new(HashMap::new()),
116 reset_tokens: RwLock::new(HashMap::new()),
117 }
118 }
119
120 pub async fn register_user(&self, username: &str, password: &str, email: &str) -> Result<String, SyncError> {
122 self.validate_password(password)?;
124
125 let users = self.users.read().await;
127 if users.values().any(|u| u.username == username || u.email == email) {
128 return Err(SyncError::AuthenticationError("User already exists".to_string()));
129 }
130 drop(users);
131
132 let user_id = self.generate_user_id();
134
135 let (password_hash, salt) = self.hash_password(password)?;
137
138 let user = User {
140 id: user_id.clone(),
141 username: username.to_string(),
142 email: email.to_string(),
143 password_hash,
144 salt,
145 created_at: Utc::now(),
146 last_login: None,
147 is_active: true,
148 is_verified: false,
149 mfa_enabled: false,
150 mfa_secret: None,
151 failed_login_attempts: 0,
152 locked_until: None,
153 };
154
155 let mut users = self.users.write().await;
157 users.insert(user_id.clone(), user);
158
159 Ok(user_id)
160 }
161
162 pub async fn login(&self, username: &str, password: &str) -> Result<UserSession, SyncError> {
164 let user = self.find_user_by_username(username).await?;
166
167 if let Some(locked_until) = user.locked_until {
169 if Utc::now() < locked_until {
170 return Err(SyncError::AuthenticationError("Account is locked".to_string()));
171 }
172 }
173
174 if !user.is_active {
176 return Err(SyncError::AuthenticationError("Account is inactive".to_string()));
177 }
178
179 if !self.verify_password(password, &user.password_hash, &user.salt)? {
181 self.increment_failed_attempts(&user.id).await?;
183 return Err(SyncError::AuthenticationError("Invalid credentials".to_string()));
184 }
185
186 if user.mfa_enabled {
188 return Err(SyncError::AuthenticationError("MFA required - use login_with_mfa method".to_string()));
189 }
190
191 self.reset_failed_attempts(&user.id).await?;
193
194 self.update_last_login(&user.id).await?;
196
197 let session = self.create_session(&user.id).await?;
199
200 Ok(session)
201 }
202
203 pub async fn login_with_mfa(&self, username: &str, password: &str, mfa_code: &str) -> Result<UserSession, SyncError> {
205 let user = self.find_user_by_username(username).await?;
207
208 if let Some(locked_until) = user.locked_until {
210 if Utc::now() < locked_until {
211 return Err(SyncError::AuthenticationError("Account is locked".to_string()));
212 }
213 }
214
215 if !user.is_active {
217 return Err(SyncError::AuthenticationError("Account is inactive".to_string()));
218 }
219
220 if !self.verify_password(password, &user.password_hash, &user.salt)? {
222 self.increment_failed_attempts(&user.id).await?;
223 return Err(SyncError::AuthenticationError("Invalid credentials".to_string()));
224 }
225
226 if !user.mfa_enabled {
228 return Err(SyncError::AuthenticationError("MFA not enabled for user".to_string()));
229 }
230
231 if !self.verify_mfa_code(&user.id, mfa_code).await? {
233 self.increment_failed_attempts(&user.id).await?;
234 return Err(SyncError::AuthenticationError("Invalid MFA code".to_string()));
235 }
236
237 self.reset_failed_attempts(&user.id).await?;
239
240 self.update_last_login(&user.id).await?;
242
243 let session = self.create_session(&user.id).await?;
245
246 Ok(session)
247 }
248
249 pub async fn validate_session(&self, token: &str) -> Result<bool, SyncError> {
251 let sessions = self.sessions.read().await;
252 if let Some(session) = sessions.get(token) {
253 if Utc::now() > session.expires_at {
255 drop(sessions);
256 self.logout(token).await?;
257 return Ok(false);
258 }
259
260 drop(sessions);
262 self.update_session_activity(token).await?;
263 Ok(true)
264 } else {
265 Ok(false)
266 }
267 }
268
269 pub async fn logout(&self, token: &str) -> Result<(), SyncError> {
271 let mut sessions = self.sessions.write().await;
272 sessions.remove(token);
273 Ok(())
274 }
275
276 pub async fn initiate_password_reset(&self, username: &str) -> Result<String, SyncError> {
278 let user = self.find_user_by_username(username).await?;
279
280 let token = self.generate_reset_token();
282 let expires_at = Utc::now() + Duration::hours(1);
283
284 let reset_token = PasswordResetToken {
285 token: token.clone(),
286 user_id: user.id.clone(),
287 expires_at,
288 created_at: Utc::now(),
289 used: false,
290 };
291
292 let mut reset_tokens = self.reset_tokens.write().await;
294 reset_tokens.insert(token.clone(), reset_token);
295
296 Ok(token)
297 }
298
299 pub async fn complete_password_reset(&self, token: &str, new_password: &str) -> Result<(), SyncError> {
301 self.validate_password(new_password)?;
303
304 let mut reset_tokens = self.reset_tokens.write().await;
306 if let Some(reset_token) = reset_tokens.get_mut(token) {
307 if Utc::now() > reset_token.expires_at {
309 return Err(SyncError::AuthenticationError("Reset token has expired".to_string()));
310 }
311
312 if reset_token.used {
314 return Err(SyncError::AuthenticationError("Reset token has already been used".to_string()));
315 }
316
317 reset_token.used = true;
319
320 let (password_hash, salt) = self.hash_password(new_password)?;
322 let mut users = self.users.write().await;
323 if let Some(user) = users.get_mut(&reset_token.user_id) {
324 user.password_hash = password_hash;
325 user.salt = salt;
326 user.failed_login_attempts = 0;
327 user.locked_until = None;
328 }
329
330 Ok(())
331 } else {
332 Err(SyncError::AuthenticationError("Invalid reset token".to_string()))
333 }
334 }
335
336 pub async fn enable_mfa(&self, user_id: &str) -> Result<(), SyncError> {
338 let mut users = self.users.write().await;
339 if let Some(user) = users.get_mut(user_id) {
340 user.mfa_enabled = true;
341 user.mfa_secret = Some(self.generate_mfa_secret());
342 } else {
343 return Err(SyncError::AuthenticationError("User not found".to_string()));
344 }
345 Ok(())
346 }
347
348 pub async fn generate_mfa_code(&self, user_id: &str) -> Result<String, SyncError> {
350 let users = self.users.read().await;
351 if let Some(user) = users.get(user_id) {
352 if let Some(secret) = &user.mfa_secret {
353 let code = self.generate_totp_code(secret);
355 Ok(code)
356 } else {
357 Err(SyncError::AuthenticationError("MFA secret not found".to_string()))
358 }
359 } else {
360 Err(SyncError::AuthenticationError("User not found".to_string()))
361 }
362 }
363
364 async fn find_user_by_username(&self, username: &str) -> Result<User, SyncError> {
366 let users = self.users.read().await;
367 users.values()
368 .find(|u| u.username == username)
369 .cloned()
370 .ok_or_else(|| SyncError::AuthenticationError("User not found".to_string()))
371 }
372
373 fn hash_password(&self, password: &str) -> Result<(String, String), SyncError> {
375 let salt = self.generate_salt();
376 let mut hasher = Sha256::new();
377 hasher.update(password.as_bytes());
378 hasher.update(salt.as_bytes());
379 let hash = hasher.finalize();
380 let hash_string = general_purpose::STANDARD.encode(hash);
381 Ok((hash_string, salt))
382 }
383
384 fn verify_password(&self, password: &str, hash: &str, salt: &str) -> Result<bool, SyncError> {
386 let mut hasher = Sha256::new();
387 hasher.update(password.as_bytes());
388 hasher.update(salt.as_bytes());
389 let computed_hash = hasher.finalize();
390 let computed_hash_string = general_purpose::STANDARD.encode(computed_hash);
391 Ok(computed_hash_string == hash)
392 }
393
394 fn validate_password(&self, password: &str) -> Result<(), SyncError> {
396 if password.len() < self.config.password_min_length {
397 return Err(SyncError::AuthenticationError(format!(
398 "Password must be at least {} characters long",
399 self.config.password_min_length
400 )));
401 }
402
403 if self.config.require_uppercase && !password.chars().any(|c| c.is_uppercase()) {
404 return Err(SyncError::AuthenticationError("Password must contain at least one uppercase letter".to_string()));
405 }
406
407 if self.config.require_lowercase && !password.chars().any(|c| c.is_lowercase()) {
408 return Err(SyncError::AuthenticationError("Password must contain at least one lowercase letter".to_string()));
409 }
410
411 if self.config.require_numbers && !password.chars().any(|c| c.is_numeric()) {
412 return Err(SyncError::AuthenticationError("Password must contain at least one number".to_string()));
413 }
414
415 if self.config.require_special_chars && !password.chars().any(|c| "!@#$%^&*()_+-=[]{}|;:,.<>?".contains(c)) {
416 return Err(SyncError::AuthenticationError("Password must contain at least one special character".to_string()));
417 }
418
419 Ok(())
420 }
421
422 fn generate_user_id(&self) -> String {
424 let mut rng = OsRng;
425 let random_bytes: [u8; 16] = rng.r#gen();
426 format!("user_{}", general_purpose::STANDARD.encode(random_bytes))
427 }
428
429 fn generate_salt(&self) -> String {
431 let mut rng = OsRng;
432 let random_bytes: [u8; 16] = rng.r#gen();
433 general_purpose::STANDARD.encode(random_bytes)
434 }
435
436 fn generate_session_token(&self) -> String {
438 let mut rng = OsRng;
439 let random_bytes: [u8; 32] = rng.r#gen();
440 general_purpose::STANDARD.encode(random_bytes)
441 }
442
443 fn generate_reset_token(&self) -> String {
445 let mut rng = OsRng;
446 let random_bytes: [u8; 32] = rng.r#gen();
447 general_purpose::STANDARD.encode(random_bytes)
448 }
449
450 fn generate_mfa_secret(&self) -> String {
452 let mut rng = OsRng;
453 let random_bytes: [u8; 20] = rng.r#gen();
454 general_purpose::STANDARD.encode(random_bytes)
455 }
456
457 fn generate_totp_code(&self, secret: &str) -> String {
459 let timestamp = Utc::now().timestamp() / 30;
461 let mut hasher = Sha256::new();
462 hasher.update(secret.as_bytes());
463 hasher.update(timestamp.to_be_bytes());
464 let hash = hasher.finalize();
465 let code = (hash[0] as u32 % 1000000) as u32;
466 format!("{:06}", code)
467 }
468
469 async fn create_session(&self, user_id: &str) -> Result<UserSession, SyncError> {
471 let token = self.generate_session_token();
472 let now = Utc::now();
473 let expires_at = now + self.config.session_timeout;
474
475 let session = UserSession {
476 user_id: user_id.to_string(),
477 token: token.clone(),
478 expires_at,
479 created_at: now,
480 last_activity: now,
481 ip_address: None,
482 user_agent: None,
483 };
484
485 let mut sessions = self.sessions.write().await;
486 sessions.insert(token, session.clone());
487
488 Ok(session)
489 }
490
491 async fn update_session_activity(&self, token: &str) -> Result<(), SyncError> {
493 let mut sessions = self.sessions.write().await;
494 if let Some(session) = sessions.get_mut(token) {
495 session.last_activity = Utc::now();
496 }
497 Ok(())
498 }
499
500 async fn increment_failed_attempts(&self, user_id: &str) -> Result<(), SyncError> {
502 let mut users = self.users.write().await;
503 if let Some(user) = users.get_mut(user_id) {
504 user.failed_login_attempts += 1;
505 if user.failed_login_attempts >= self.config.max_failed_attempts {
506 user.locked_until = Some(Utc::now() + self.config.lockout_duration);
507 }
508 }
509 Ok(())
510 }
511
512 async fn reset_failed_attempts(&self, user_id: &str) -> Result<(), SyncError> {
514 let mut users = self.users.write().await;
515 if let Some(user) = users.get_mut(user_id) {
516 user.failed_login_attempts = 0;
517 user.locked_until = None;
518 }
519 Ok(())
520 }
521
522 async fn update_last_login(&self, user_id: &str) -> Result<(), SyncError> {
524 let mut users = self.users.write().await;
525 if let Some(user) = users.get_mut(user_id) {
526 user.last_login = Some(Utc::now());
527 }
528 Ok(())
529 }
530
531 async fn verify_mfa_code(&self, user_id: &str, code: &str) -> Result<bool, SyncError> {
533 let users = self.users.read().await;
534 if let Some(user) = users.get(user_id) {
535 if let Some(secret) = &user.mfa_secret {
536 let expected_code = self.generate_totp_code(secret);
537 Ok(expected_code == code)
538 } else {
539 Ok(false)
540 }
541 } else {
542 Ok(false)
543 }
544 }
545
546 pub async fn get_user(&self, user_id: &str) -> Result<User, SyncError> {
548 let users = self.users.read().await;
549 users.get(user_id)
550 .cloned()
551 .ok_or_else(|| SyncError::AuthenticationError("User not found".to_string()))
552 }
553
554 pub async fn list_users(&self) -> Vec<User> {
556 let users = self.users.read().await;
557 users.values().cloned().collect()
558 }
559
560 pub async fn cleanup_expired_sessions(&self) -> usize {
562 let mut sessions = self.sessions.write().await;
563 let now = Utc::now();
564 let expired_tokens: Vec<String> = sessions
565 .iter()
566 .filter(|(_, session)| session.expires_at < now)
567 .map(|(token, _)| token.clone())
568 .collect();
569
570 for token in &expired_tokens {
571 sessions.remove(token);
572 }
573
574 expired_tokens.len()
575 }
576
577 pub async fn cleanup_expired_reset_tokens(&self) -> usize {
579 let mut reset_tokens = self.reset_tokens.write().await;
580 let now = Utc::now();
581 let expired_tokens: Vec<String> = reset_tokens
582 .iter()
583 .filter(|(_, token)| token.expires_at < now)
584 .map(|(token, _)| token.clone())
585 .collect();
586
587 for token in &expired_tokens {
588 reset_tokens.remove(token);
589 }
590
591 expired_tokens.len()
592 }
593}
594
595#[cfg(test)]
596mod tests {
597 use super::*;
598
599 #[tokio::test]
600 async fn test_user_registration() {
601 let auth_manager = AuthenticationManager::new();
602 let username = "test_user";
603 let password = "SecurePassword123!";
604 let email = "test@example.com";
605
606 let result = auth_manager.register_user(username, password, email).await;
607 assert!(result.is_ok());
608
609 let user_id = result.unwrap();
610 assert!(!user_id.is_empty());
611 }
612
613 #[tokio::test]
614 async fn test_user_login() {
615 let auth_manager = AuthenticationManager::new();
616 let username = "test_user";
617 let password = "SecurePassword123!";
618 let email = "test@example.com";
619
620 let user_id = auth_manager.register_user(username, password, email).await.unwrap();
622
623 let session = auth_manager.login(username, password).await.unwrap();
625 assert_eq!(session.user_id, user_id);
626 assert!(!session.token.is_empty());
627 assert!(session.expires_at > Utc::now());
628 }
629
630 #[tokio::test]
631 async fn test_invalid_login() {
632 let auth_manager = AuthenticationManager::new();
633 let username = "test_user";
634 let password = "SecurePassword123!";
635 let wrong_password = "WrongPassword123!";
636
637 auth_manager.register_user(username, password, "test@example.com").await.unwrap();
639
640 let result = auth_manager.login(username, wrong_password).await;
642 assert!(result.is_err());
643 }
644
645 #[tokio::test]
646 async fn test_session_validation() {
647 let auth_manager = AuthenticationManager::new();
648 let username = "test_user";
649 let password = "SecurePassword123!";
650
651 auth_manager.register_user(username, password, "test@example.com").await.unwrap();
653 let session = auth_manager.login(username, password).await.unwrap();
654
655 let is_valid = auth_manager.validate_session(&session.token).await.unwrap();
657 assert!(is_valid);
658
659 auth_manager.logout(&session.token).await.unwrap();
661
662 let is_valid_after_logout = auth_manager.validate_session(&session.token).await.unwrap();
664 assert!(!is_valid_after_logout);
665 }
666
667 #[tokio::test]
668 async fn test_password_reset() {
669 let auth_manager = AuthenticationManager::new();
670 let username = "test_user";
671 let old_password = "OldPassword123!";
672 let new_password = "NewPassword123!";
673
674 auth_manager.register_user(username, old_password, "test@example.com").await.unwrap();
676
677 let reset_token = auth_manager.initiate_password_reset(username).await.unwrap();
679 assert!(!reset_token.is_empty());
680
681 auth_manager.complete_password_reset(&reset_token, new_password).await.unwrap();
683
684 let old_login_result = auth_manager.login(username, old_password).await;
686 assert!(old_login_result.is_err());
687
688 let new_login_result = auth_manager.login(username, new_password).await;
690 assert!(new_login_result.is_ok());
691 }
692
693 #[tokio::test]
694 async fn test_multi_factor_authentication() {
695 let auth_manager = AuthenticationManager::new();
696 let username = "test_user";
697 let password = "SecurePassword123!";
698
699 let user_id = auth_manager.register_user(username, password, "test@example.com").await.unwrap();
701 auth_manager.enable_mfa(&user_id).await.unwrap();
702
703 let login_result = auth_manager.login(username, password).await;
705 assert!(login_result.is_err()); let mfa_code = auth_manager.generate_mfa_code(&user_id).await.unwrap();
709
710 let session = auth_manager.login_with_mfa(username, password, &mfa_code).await.unwrap();
712 assert!(!session.token.is_empty());
713 }
714
715 #[tokio::test]
716 async fn test_password_validation() {
717 let auth_manager = AuthenticationManager::new();
718
719 let weak_password = "123";
721 let result = auth_manager.register_user("user1", weak_password, "test1@example.com").await;
722 assert!(result.is_err());
723
724 let no_upper = "password123!";
726 let result = auth_manager.register_user("user2", no_upper, "test2@example.com").await;
727 assert!(result.is_err());
728
729 let no_lower = "PASSWORD123!";
731 let result = auth_manager.register_user("user3", no_lower, "test3@example.com").await;
732 assert!(result.is_err());
733
734 let no_numbers = "Password!";
736 let result = auth_manager.register_user("user4", no_numbers, "test4@example.com").await;
737 assert!(result.is_err());
738
739 let no_special = "Password123";
741 let result = auth_manager.register_user("user5", no_special, "test5@example.com").await;
742 assert!(result.is_err());
743
744 let valid_password = "SecurePassword123!";
746 let result = auth_manager.register_user("user6", valid_password, "test6@example.com").await;
747 assert!(result.is_ok());
748 }
749
750 #[tokio::test]
751 async fn test_account_lockout() {
752 let auth_manager = AuthenticationManager::new();
753 let username = "test_user";
754 let password = "SecurePassword123!";
755 let wrong_password = "WrongPassword123!";
756
757 auth_manager.register_user(username, password, "test@example.com").await.unwrap();
759
760 for _ in 0..5 {
762 let _ = auth_manager.login(username, wrong_password).await;
763 }
764
765 let result = auth_manager.login(username, password).await;
767 assert!(result.is_err());
768 assert!(result.unwrap_err().to_string().contains("locked"));
769 }
770
771 #[tokio::test]
772 async fn test_duplicate_user_registration() {
773 let auth_manager = AuthenticationManager::new();
774 let username = "test_user";
775 let password = "SecurePassword123!";
776 let email = "test@example.com";
777
778 let result1 = auth_manager.register_user(username, password, email).await;
780 assert!(result1.is_ok());
781
782 let result2 = auth_manager.register_user(username, password, email).await;
784 assert!(result2.is_err());
785 assert!(result2.unwrap_err().to_string().contains("already exists"));
786 }
787
788 #[tokio::test]
789 async fn test_session_cleanup() {
790 let auth_manager = AuthenticationManager::new();
791 let username = "test_user";
792 let password = "SecurePassword123!";
793
794 auth_manager.register_user(username, password, "test@example.com").await.unwrap();
796 let session = auth_manager.login(username, password).await.unwrap();
797
798 let is_valid = auth_manager.validate_session(&session.token).await.unwrap();
800 assert!(is_valid);
801
802 let cleaned = auth_manager.cleanup_expired_sessions().await;
804 assert_eq!(cleaned, 0);
805
806 let is_valid_after_cleanup = auth_manager.validate_session(&session.token).await.unwrap();
808 assert!(is_valid_after_cleanup);
809 }
810}