1use crate::config::AuthConfig;
4use crate::credentials::{Credential, CredentialMetadata};
5use crate::errors::{AuthError, MfaError, Result};
6use crate::methods::{AuthMethod, MfaChallenge, MethodResult};
7use crate::permissions::{Permission, PermissionChecker};
8use crate::storage::{AuthStorage, MemoryStorage, SessionData};
9use crate::tokens::{AuthToken, TokenManager};
10use crate::utils::rate_limit::RateLimiter;
11use std::collections::HashMap;
12use std::sync::Arc;
13use std::time::Duration;
14use tokio::sync::RwLock;
15use tracing::{debug, info, warn, error};
16
17#[derive(Debug, Clone)]
19pub enum AuthResult {
20 Success(Box<AuthToken>),
22
23 MfaRequired(Box<MfaChallenge>),
25
26 Failure(String),
28}
29
30#[derive(Debug, Clone)]
32pub struct UserInfo {
33 pub id: String,
35
36 pub username: String,
38
39 pub email: Option<String>,
41
42 pub name: Option<String>,
44
45 pub roles: Vec<String>,
47
48 pub active: bool,
50
51 pub attributes: HashMap<String, serde_json::Value>,
53}
54
55pub struct AuthFramework {
57 config: AuthConfig,
59
60 methods: HashMap<String, Box<dyn AuthMethod>>,
62
63 token_manager: TokenManager,
65
66 storage: Arc<dyn AuthStorage>,
68
69 permission_checker: Arc<RwLock<PermissionChecker>>,
71
72 rate_limiter: Option<RateLimiter>,
74
75 mfa_challenges: Arc<RwLock<HashMap<String, MfaChallenge>>>,
77
78 sessions: Arc<RwLock<HashMap<String, SessionData>>>,
80
81 initialized: bool,
83}
84
85impl AuthFramework {
86 pub fn new(config: AuthConfig) -> Self {
88 config.validate().expect("Invalid configuration");
90
91 let token_manager = if let Some(secret) = &config.security.secret_key {
93 TokenManager::new_hmac(
94 secret.as_bytes(),
95 "auth-framework",
96 "auth-framework",
97 )
98 } else {
99 TokenManager::new_hmac(
100 b"default-secret-key", "auth-framework",
102 "auth-framework",
103 )
104 };
105
106 let storage: Arc<dyn AuthStorage> = match &config.storage {
108 #[cfg(feature = "redis-storage")]
109 crate::config::StorageConfig::Redis { url, key_prefix } => {
110 Arc::new(crate::storage::RedisStorage::new(url, key_prefix)
111 .expect("Failed to create Redis storage"))
112 }
113 _ => Arc::new(MemoryStorage::new()),
114 };
115
116 let rate_limiter = if config.rate_limiting.enabled {
118 Some(RateLimiter::new(
119 config.rate_limiting.max_requests,
120 config.rate_limiting.window,
121 ))
122 } else {
123 None
124 };
125
126 Self {
127 config,
128 methods: HashMap::new(),
129 token_manager,
130 storage,
131 permission_checker: Arc::new(RwLock::new(PermissionChecker::new())),
132 rate_limiter,
133 mfa_challenges: Arc::new(RwLock::new(HashMap::new())),
134 sessions: Arc::new(RwLock::new(HashMap::new())),
135 initialized: false,
136 }
137 }
138
139 pub fn register_method(&mut self, name: impl Into<String>, method: Box<dyn AuthMethod>) {
141 let name = name.into();
142 info!("Registering authentication method: {}", name);
143
144 if let Err(e) = method.validate_config() {
146 error!("Method '{}' configuration validation failed: {}", name, e);
147 return;
148 }
149
150 self.methods.insert(name, method);
151 }
152
153 pub async fn initialize(&mut self) -> Result<()> {
155 if self.initialized {
156 return Ok(());
157 }
158
159 info!("Initializing authentication framework");
160
161 {
163 let mut checker = self.permission_checker.write().await;
164 checker.create_default_roles();
165 }
166
167 self.cleanup_expired_data().await?;
169
170 self.initialized = true;
171 info!("Authentication framework initialized successfully");
172
173 Ok(())
174 }
175
176 pub async fn authenticate(
178 &self,
179 method_name: &str,
180 credential: Credential,
181 ) -> Result<AuthResult> {
182 self.authenticate_with_metadata(method_name, credential, CredentialMetadata::new()).await
183 }
184
185 pub async fn authenticate_with_metadata(
187 &self,
188 method_name: &str,
189 credential: Credential,
190 metadata: CredentialMetadata,
191 ) -> Result<AuthResult> {
192 if !self.initialized {
193 return Err(AuthError::internal("Framework not initialized"));
194 }
195
196 if let Some(ref rate_limiter) = self.rate_limiter {
198 let rate_key = format!("auth:{}:{}",
199 method_name,
200 metadata.client_ip.as_deref().unwrap_or("unknown")
201 );
202
203 if !rate_limiter.is_allowed(&rate_key) {
204 warn!("Rate limit exceeded for method '{}' from IP {:?}",
205 method_name, metadata.client_ip);
206 return Err(AuthError::rate_limit("Too many authentication attempts"));
207 }
208 }
209
210 let method = self.methods.get(method_name)
212 .ok_or_else(|| AuthError::auth_method(
213 method_name,
214 "Authentication method not found".to_string(),
215 ))?;
216
217 debug!("Authentication attempt with method '{}' for credential: {}",
219 method_name, credential.safe_display());
220
221 let result = method.authenticate(&credential, &metadata).await?;
223
224 match &result {
226 MethodResult::Success(token) => {
227 info!("Authentication successful for user '{}' with method '{}'",
228 token.user_id, method_name);
229
230 self.storage.store_token(token).await?;
232
233 self.log_audit_event("auth_success", &token.user_id, method_name, &metadata).await;
235
236 Ok(AuthResult::Success(token.clone()))
237 }
238
239 MethodResult::MfaRequired(challenge) => {
240 info!("MFA required for user '{}' with method '{}'",
241 challenge.user_id, method_name);
242
243 let mut challenges = self.mfa_challenges.write().await;
245 challenges.insert(challenge.id.clone(), (**challenge).clone());
246
247 self.log_audit_event("mfa_required", &challenge.user_id, method_name, &metadata).await;
249
250 Ok(AuthResult::MfaRequired(challenge.clone()))
251 }
252
253 MethodResult::Failure { reason } => {
254 warn!("Authentication failed for method '{}': {}", method_name, reason);
255
256 self.log_audit_event("auth_failure", "unknown", method_name, &metadata).await;
258
259 Ok(AuthResult::Failure(reason.clone()))
260 }
261 }
262 }
263
264 pub async fn complete_mfa(
266 &self,
267 challenge: MfaChallenge,
268 mfa_code: &str,
269 ) -> Result<AuthToken> {
270 debug!("Completing MFA for challenge '{}'", challenge.id);
271
272 let mut challenges = self.mfa_challenges.write().await;
274 let stored_challenge = challenges.get(&challenge.id)
275 .ok_or(MfaError::ChallengeExpired)?;
276
277 if stored_challenge.is_expired() {
278 challenges.remove(&challenge.id);
279 return Err(MfaError::ChallengeExpired.into());
280 }
281
282 if !self.verify_mfa_code(stored_challenge, mfa_code).await? {
284 return Err(MfaError::InvalidCode.into());
285 }
286
287 challenges.remove(&challenge.id);
289
290 let token = self.token_manager.create_auth_token(
292 &challenge.user_id,
293 vec![], "mfa",
295 None,
296 )?;
297
298 self.storage.store_token(&token).await?;
300
301 info!("MFA completed successfully for user '{}'", challenge.user_id);
302
303 Ok(token)
304 }
305
306 pub async fn validate_token(&self, token: &AuthToken) -> Result<bool> {
308 if !token.is_valid() {
310 return Ok(false);
311 }
312
313 self.token_manager.validate_auth_token(token)?;
315
316 if let Some(stored_token) = self.storage.get_token(&token.token_id).await? {
318 let mut updated_token = stored_token;
320 updated_token.mark_used();
321 self.storage.update_token(&updated_token).await?;
322
323 Ok(true)
324 } else {
325 Ok(false)
326 }
327 }
328
329 pub async fn get_user_info(&self, token: &AuthToken) -> Result<UserInfo> {
331 if !self.validate_token(token).await? {
332 return Err(AuthError::auth_method("token", "Invalid token".to_string()));
333 }
334
335 let token_info = self.token_manager.extract_token_info(&token.access_token)?;
337
338 Ok(UserInfo {
339 id: token_info.user_id,
340 username: token_info.username.unwrap_or_else(|| "unknown".to_string()),
341 email: token_info.email,
342 name: token_info.name,
343 roles: token_info.roles,
344 active: true, attributes: token_info.attributes,
346 })
347 }
348
349 pub async fn check_permission(
351 &self,
352 token: &AuthToken,
353 action: &str,
354 resource: &str,
355 ) -> Result<bool> {
356 if !self.validate_token(token).await? {
357 return Ok(false);
358 }
359
360 let permission = Permission::new(action, resource);
361 let mut checker = self.permission_checker.write().await;
362 checker.check_token_permission(token, &permission)
363 }
364
365 pub async fn refresh_token(&self, token: &AuthToken) -> Result<AuthToken> {
367 debug!("Refreshing token for user '{}'", token.user_id);
368
369 if let Some(method) = self.methods.get(&token.auth_method) {
371 if method.supports_refresh() {
372 if let Some(ref refresh_token) = token.refresh_token {
373 let new_token = method.refresh_token(refresh_token).await?;
374 self.storage.store_token(&new_token).await?;
375 return Ok(new_token);
376 }
377 }
378 }
379
380 let new_token = self.token_manager.refresh_token(token)?;
382 self.storage.store_token(&new_token).await?;
383
384 info!("Token refreshed for user '{}'", token.user_id);
385
386 Ok(new_token)
387 }
388
389 pub async fn revoke_token(&self, token: &AuthToken) -> Result<()> {
391 debug!("Revoking token for user '{}'", token.user_id);
392
393 let mut revoked_token = token.clone();
395 revoked_token.revoke(Some("Manual revocation".to_string()));
396
397 self.storage.update_token(&revoked_token).await?;
399
400 info!("Token revoked for user '{}'", token.user_id);
401
402 Ok(())
403 }
404
405 pub async fn create_api_key(&self, user_id: &str, expires_in: Option<Duration>) -> Result<String> {
407 debug!("Creating API key for user '{}'", user_id);
408
409 let api_key = format!("ak_{}", crate::utils::crypto::generate_token(32));
411
412 let token = self.token_manager.create_auth_token(
414 user_id,
415 vec!["api".to_string()],
416 "api-key",
417 expires_in,
418 )?;
419
420 self.storage.store_token(&token).await?;
422
423 info!("API key created for user '{}'", user_id);
424
425 Ok(api_key)
426 }
427
428 pub async fn create_session(
430 &self,
431 user_id: &str,
432 expires_in: Duration,
433 ip_address: Option<String>,
434 user_agent: Option<String>,
435 ) -> Result<String> {
436 let session_id = crate::utils::string::generate_id(Some("sess"));
437 let session = SessionData::new(session_id.clone(), user_id, expires_in)
438 .with_metadata(ip_address, user_agent);
439
440 self.storage.store_session(&session_id, &session).await?;
441
442 info!("Session created for user '{}'", user_id);
443
444 Ok(session_id)
445 }
446
447 pub async fn get_session(&self, session_id: &str) -> Result<Option<SessionData>> {
449 self.storage.get_session(session_id).await
450 }
451
452 pub async fn delete_session(&self, session_id: &str) -> Result<()> {
454 self.storage.delete_session(session_id).await?;
455 info!("Session '{}' deleted", session_id);
456 Ok(())
457 }
458
459 pub async fn list_user_tokens(&self, user_id: &str) -> Result<Vec<AuthToken>> {
461 self.storage.list_user_tokens(user_id).await
462 }
463
464 pub async fn cleanup_expired_data(&self) -> Result<()> {
466 debug!("Cleaning up expired data");
467
468 self.storage.cleanup_expired().await?;
470
471 {
473 let mut challenges = self.mfa_challenges.write().await;
474 let now = chrono::Utc::now();
475 challenges.retain(|_, challenge| challenge.expires_at > now);
476 }
477
478 {
480 let mut sessions = self.sessions.write().await;
481 let now = chrono::Utc::now();
482 sessions.retain(|_, session| session.expires_at > now);
483 }
484
485 if let Some(ref rate_limiter) = self.rate_limiter {
487 rate_limiter.cleanup();
488 }
489
490 Ok(())
491 }
492
493 pub async fn get_stats(&self) -> Result<AuthStats> {
495 let mut stats = AuthStats::default();
496
497 let _user_tokens: HashMap<String, u32> = HashMap::new();
500 for method in self.methods.keys() {
501 stats.registered_methods.push(method.clone());
502 }
503
504 stats.active_sessions = self.sessions.read().await.len() as u64;
505 stats.active_mfa_challenges = self.mfa_challenges.read().await.len() as u64;
506
507 Ok(stats)
508 }
509
510 async fn verify_mfa_code(&self, _challenge: &MfaChallenge, _code: &str) -> Result<bool> {
512 Ok(true)
515 }
516
517 async fn log_audit_event(
519 &self,
520 event_type: &str,
521 user_id: &str,
522 method: &str,
523 metadata: &CredentialMetadata,
524 ) {
525 if self.config.audit.enabled {
526 let should_log = match event_type {
527 "auth_success" => self.config.audit.log_success,
528 "auth_failure" => self.config.audit.log_failures,
529 "mfa_required" => self.config.audit.log_success,
530 _ => true,
531 };
532
533 if should_log {
534 info!(
535 target: "auth_audit",
536 event_type = event_type,
537 user_id = user_id,
538 method = method,
539 client_ip = metadata.client_ip.as_deref().unwrap_or("unknown"),
540 user_agent = metadata.user_agent.as_deref().unwrap_or("unknown"),
541 timestamp = chrono::Utc::now().to_rfc3339(),
542 "Authentication event"
543 );
544 }
545 }
546 }
547
548 pub async fn create_auth_token(
552 &self,
553 user_id: impl Into<String>,
554 scopes: Vec<String>,
555 method_name: impl Into<String>,
556 lifetime: Option<Duration>,
557 ) -> Result<AuthToken> {
558 let method_name = method_name.into();
559 let user_id = user_id.into();
560
561 let _method = self.methods.get(&method_name)
563 .ok_or_else(|| AuthError::auth_method(&method_name, "Method not found"))?;
564
565 let jwt_token = self.token_manager.create_jwt_token(
567 &user_id,
568 scopes.clone(),
569 lifetime,
570 )?;
571
572 let token = AuthToken::new(
574 user_id,
575 jwt_token,
576 lifetime.unwrap_or(Duration::from_secs(3600)),
577 method_name,
578 ).with_scopes(scopes);
579
580 self.storage.store_token(&token).await?;
582
583 Ok(token)
584 }
585}
586
587#[derive(Debug, Clone, Default)]
589pub struct AuthStats {
590 pub registered_methods: Vec<String>,
592
593 pub active_sessions: u64,
595
596 pub active_mfa_challenges: u64,
598
599 pub tokens_issued: u64,
601
602 pub auth_attempts: u64,
604}
605
606#[cfg(test)]
607mod tests {
608 use super::*;
609 use crate::methods::JwtMethod;
610 use crate::config::AuthConfig;
611
612 #[tokio::test]
613 async fn test_framework_initialization() {
614 let config = AuthConfig::new();
615 let mut framework = AuthFramework::new(config);
616
617 assert!(framework.initialize().await.is_ok());
618 assert!(framework.initialized);
619 }
620
621 #[tokio::test]
622 async fn test_method_registration() {
623 let config = AuthConfig::new();
624 let mut framework = AuthFramework::new(config);
625
626 let jwt_method = JwtMethod::new().secret_key("test-secret");
627 framework.register_method("jwt", Box::new(jwt_method));
628
629 assert!(framework.methods.contains_key("jwt"));
630 }
631
632 #[tokio::test]
633 async fn test_token_validation() {
634 let config = AuthConfig::new();
635 let mut framework = AuthFramework::new(config);
636 framework.initialize().await.unwrap();
637
638 let token = framework.token_manager.create_auth_token(
639 "test-user",
640 vec!["read".to_string()],
641 "test",
642 None,
643 ).unwrap();
644
645 framework.storage.store_token(&token).await.unwrap();
647
648 assert!(framework.validate_token(&token).await.unwrap());
649 }
650
651 #[tokio::test]
652 async fn test_session_management() {
653 let config = AuthConfig::new();
654 let mut framework = AuthFramework::new(config);
655 framework.initialize().await.unwrap();
656
657 let session_id = framework.create_session(
658 "test-user",
659 Duration::from_secs(3600),
660 Some("192.168.1.1".to_string()),
661 Some("Test Agent".to_string()),
662 ).await.unwrap();
663
664 let session = framework.get_session(&session_id).await.unwrap();
665 assert!(session.is_some());
666
667 framework.delete_session(&session_id).await.unwrap();
668 let session = framework.get_session(&session_id).await.unwrap();
669 assert!(session.is_none());
670 }
671
672 #[tokio::test]
673 async fn test_cleanup_expired_data() {
674 let config = AuthConfig::new();
675 let mut framework = AuthFramework::new(config);
676 framework.initialize().await.unwrap();
677
678 assert!(framework.cleanup_expired_data().await.is_ok());
680 }
681}