Skip to main content

auth_framework/
auth.rs

1//! Main authentication framework implementation.
2
3use crate::auth_operations::{
4    AuditLogQuery, DelegationRequest, PermissionContext, SessionCreateRequest, UserListQuery,
5};
6use crate::authentication::credentials::{Credential, CredentialMetadata};
7use crate::config::AuthConfig;
8use crate::distributed::DistributedSessionStore;
9use crate::errors::{AuthError, MfaError, Result};
10use crate::methods::{AuthMethod, AuthMethodEnum, MethodResult, MfaChallenge};
11use crate::permissions::PermissionChecker;
12use crate::storage::{AuthStorage, MemoryStorage, SessionData};
13use crate::tokens::{AuthToken, TokenManager};
14use crate::utils::rate_limit::RateLimiter;
15use std::collections::HashMap;
16use std::sync::Arc;
17use std::time::Duration;
18use tokio::sync::RwLock;
19use tracing::{debug, error, info, warn};
20
21/// Result of an authentication attempt.
22#[derive(Debug, Clone)]
23pub enum AuthResult {
24    /// Authentication was successful
25    Success(Box<AuthToken>),
26
27    /// Multi-factor authentication is required
28    MfaRequired(Box<MfaChallenge>),
29
30    /// Authentication failed
31    Failure(String),
32}
33
34/// Information about a user.
35#[derive(Debug, Clone)]
36pub struct UserInfo {
37    /// User ID
38    pub id: String,
39
40    /// Username
41    pub username: String,
42
43    /// Email address
44    pub email: Option<String>,
45
46    /// Display name
47    pub name: Option<String>,
48
49    /// User roles
50    pub roles: crate::types::Roles,
51
52    /// Whether the user is active
53    pub active: bool,
54
55    /// Whether the user's email address has been verified
56    pub email_verified: bool,
57
58    /// Additional user attributes
59    pub attributes: crate::types::UserAttributes,
60}
61
62/// Returns true when running in a test environment.
63///
64/// Checks `cfg!(test)`, the `RUST_TEST` env var (set by `TestEnvironmentGuard`), and the
65/// `ENVIRONMENT=test` convention. This allows relaxed security constraints (e.g. short JWT
66/// secrets) in automated tests while enforcing them in production.
67///
68/// An explicit `ENVIRONMENT=production` setting always overrides → returns `false`, so tests
69/// that deliberately validate production-mode behaviour can opt out of the bypass.
70#[inline]
71fn is_test_env() -> bool {
72    // An explicit production override always wins — never bypass security checks.
73    if std::env::var("ENVIRONMENT").as_deref() == Ok("production") {
74        return false;
75    }
76    cfg!(test)
77        || std::env::var("RUST_TEST").is_ok()
78        || std::env::var("ENVIRONMENT").as_deref() == Ok("test")
79}
80
81/// The primary authentication and authorization framework for Rust applications.
82///
83/// `AuthFramework` is the central component that orchestrates all authentication
84/// and authorization operations. It provides a unified interface for multiple
85/// authentication methods, token management, session handling, and security monitoring.
86///
87/// # Core Capabilities
88///
89/// - **Multi-Method Authentication**: Support for password, OAuth2, MFA, passkeys, and custom methods
90/// - **Token Management**: JWT token creation, validation, and lifecycle management
91/// - **Session Management**: Secure session handling with configurable storage backends
92/// - **Permission System**: Role-based and resource-based authorization
93/// - **Security Monitoring**: Real-time threat detection and audit logging
94/// - **Rate Limiting**: Configurable rate limiting for brute force protection
95///
96/// # Thread Safety
97///
98/// The framework is designed for concurrent use and can be safely shared across
99/// multiple threads using `Arc<AuthFramework>`.
100///
101/// # Storage Backends
102///
103/// Supports multiple storage backends:
104/// - In-memory (for development/testing)
105/// - Redis (for production with clustering)
106/// - PostgreSQL (for persistent storage)
107/// - Custom implementations via the `AuthStorage` trait
108///
109/// # Example
110///
111/// ```rust,no_run
112/// use auth_framework::{AuthFramework, AuthConfig};
113/// use auth_framework::authentication::credentials::Credential;
114/// use auth_framework::methods::AuthMethodEnum;
115///
116/// # #[tokio::main]
117/// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
118/// // Create framework with default configuration
119/// let config = AuthConfig::default();
120/// let mut auth = AuthFramework::new(config);
121///
122/// // Register an authentication method
123/// # let password_method: AuthMethodEnum = unimplemented!();
124/// auth.register_method("password", password_method);
125///
126/// // Authenticate a user
127/// # let credential: Credential = unimplemented!();
128/// let result = auth.authenticate("password", credential).await?;
129/// # Ok(())
130/// # }
131/// ```
132///
133/// # Security Considerations
134///
135/// - All tokens are signed with cryptographically secure keys
136/// - Session data is encrypted at rest when using persistent storage
137/// - Rate limiting prevents brute force attacks
138/// - Audit logging captures all security-relevant events
139/// - Configurable security policies for enterprise compliance
140pub struct AuthFramework {
141    /// Configuration
142    config: AuthConfig,
143
144    /// Registered authentication methods
145    methods: HashMap<String, AuthMethodEnum>,
146
147    /// Token manager
148    token_manager: TokenManager,
149
150    /// Storage backend
151    storage: Arc<dyn AuthStorage>,
152
153    /// Authorization manager for role/permission operations
154    authorization_manager: crate::auth_modular::authorization_manager::AuthorizationManager,
155
156    /// Rate limiter
157    rate_limiter: Option<RateLimiter>,
158
159    /// Monitoring manager for metrics and health checks
160    monitoring_manager: Arc<crate::monitoring::MonitoringManager>,
161
162    /// Audit manager for security event logging
163    audit_manager: Arc<crate::audit::AuditLogger<Arc<crate::storage::MemoryStorage>>>,
164
165    /// Security manager for rate limiting, DoS protection, and IP blacklisting
166    #[cfg(feature = "api-server")]
167    security_manager: Arc<crate::api::SecurityManager>,
168
169    /// Runtime-mutable configuration. Updated live by the admin API without restart.
170    pub(crate) runtime_config: Arc<tokio::sync::RwLock<crate::config::RuntimeConfig>>,
171
172    /// Decoupled user lifecycle manager.
173    user_manager: crate::auth_modular::user_manager::UserManager,
174
175    /// Decoupled session lifecycle manager.
176    session_manager: crate::auth_modular::session_manager::SessionManager,
177
178    /// Decoupled MFA manager (TOTP, SMS, email, backup codes).
179    mfa_manager: crate::auth_modular::mfa::MfaManager,
180
181    /// Framework initialization state
182    initialized: bool,
183
184    /// Whether the caller explicitly replaced the storage backend.
185    storage_overridden: bool,
186}
187
188pub use crate::auth_operations::{
189    AdminOperations, AuditOperations, AuthorizationOperations, MaintenanceOperations,
190    MfaOperations, MonitoringOperations, SessionOperations, TokenOperations, UserOperations,
191};
192
193/// Extract JWT secret bytes from `config` or the `JWT_SECRET` env-var.
194///
195/// Tries (in order): `config.security.secret_key`, `config.secret`, `$JWT_SECRET`.
196/// Returns an error when none is present; callers in non-production environments may
197/// substitute a dev-only fallback when this function returns `Err`.
198fn resolve_jwt_secret_bytes(config: &AuthConfig) -> Result<Vec<u8>> {
199    if let Some(secret) = &config.security.secret_key {
200        if secret.len() < 32 && !is_test_env() {
201            return Err(AuthError::configuration(
202                "JWT secret must be at least 32 characters for production security",
203            ));
204        }
205        return Ok(secret.as_bytes().to_vec());
206    }
207    if let Some(secret) = &config.secret {
208        if secret.len() < 32 && !is_test_env() {
209            return Err(AuthError::configuration(
210                "JWT secret must be at least 32 characters for production security",
211            ));
212        }
213        return Ok(secret.as_bytes().to_vec());
214    }
215    if let Ok(jwt_secret) = std::env::var("JWT_SECRET") {
216        if jwt_secret.len() < 32 && !is_test_env() {
217            return Err(AuthError::configuration(
218                "JWT_SECRET must be at least 32 characters for production security",
219            ));
220        }
221        return Ok(jwt_secret.as_bytes().to_vec());
222    }
223    Err(AuthError::configuration(
224        "JWT secret not configured! Please set JWT_SECRET environment variable or provide in configuration.\n\
225           For security reasons, no default secret is provided.\n\
226           Generate a secure secret with: openssl rand -base64 32",
227    ))
228}
229
230impl AuthFramework {
231    /// Access focused user-management operations.
232    pub fn users(&self) -> UserOperations<'_> {
233        UserOperations { framework: self }
234    }
235
236    /// Access focused session-management operations.
237    pub fn sessions(&self) -> SessionOperations<'_> {
238        SessionOperations { framework: self }
239    }
240
241    /// Access focused token-management operations.
242    pub fn tokens(&self) -> TokenOperations<'_> {
243        TokenOperations { framework: self }
244    }
245
246    /// Access focused authorization operations.
247    pub fn authorization(&self) -> AuthorizationOperations<'_> {
248        AuthorizationOperations { framework: self }
249    }
250
251    /// Access focused multi-factor authentication operations.
252    pub fn mfa(&self) -> MfaOperations<'_> {
253        MfaOperations { framework: self }
254    }
255
256    /// Access focused monitoring and health operations.
257    pub fn monitoring(&self) -> MonitoringOperations<'_> {
258        MonitoringOperations { framework: self }
259    }
260
261    /// Access focused audit log operations.
262    pub fn audit(&self) -> AuditOperations<'_> {
263        AuditOperations { framework: self }
264    }
265
266    /// Access focused maintenance operations.
267    pub fn maintenance(&self) -> MaintenanceOperations<'_> {
268        MaintenanceOperations { framework: self }
269    }
270
271    /// Read the current runtime-mutable configuration.
272    pub async fn runtime_config(&self) -> crate::config::RuntimeConfig {
273        self.runtime_config.read().await.clone()
274    }
275
276    #[deprecated(since = "0.6.0", note = "Use `runtime_config()` instead")]
277    #[doc(hidden)]
278    pub async fn get_runtime_config(&self) -> crate::config::RuntimeConfig {
279        self.runtime_config().await
280    }
281
282    /// Apply a partial or full update to the runtime-mutable configuration.
283    ///
284    /// The update is applied atomically. Returns the updated configuration.
285    /// Returns `Err` if any field value is out of range (e.g. zero token lifetime).
286    pub async fn update_runtime_config(
287        &self,
288        update: crate::config::RuntimeConfig,
289    ) -> Result<crate::config::RuntimeConfig> {
290        // Basic sanity checks before persisting.
291        if update.token_lifetime_secs == 0 {
292            return Err(AuthError::config("token_lifetime_secs must be > 0"));
293        }
294        if update.refresh_token_lifetime_secs == 0 {
295            return Err(AuthError::config("refresh_token_lifetime_secs must be > 0"));
296        }
297        if update.refresh_token_lifetime_secs <= update.token_lifetime_secs {
298            return Err(AuthError::config(
299                "refresh_token_lifetime_secs must be greater than token_lifetime_secs",
300            ));
301        }
302        if update.min_password_length == 0 {
303            return Err(AuthError::config("min_password_length must be > 0"));
304        }
305        let mut cfg = self.runtime_config.write().await;
306        *cfg = update.clone();
307        Ok(update)
308    }
309
310    /// Access focused advanced administration operations (ABAC, delegation, role hierarchy).
311    pub fn admin(&self) -> AdminOperations<'_> {
312        AdminOperations { framework: self }
313    }
314
315    /// Create a new authentication framework.
316    ///
317    /// This method is infallible and creates a basic framework instance.
318    /// Configuration validation and component initialization is deferred to `initialize()`.
319    /// An ephemeral random secret is used for the token manager until `initialize()`
320    /// replaces it with the configured secret. Tokens issued before initialization
321    /// will NOT be valid afterwards.
322    pub fn new(config: AuthConfig) -> Self {
323        // Store configuration for later validation during initialize()
324        let storage = Arc::new(MemoryStorage::new()) as Arc<dyn AuthStorage>;
325        let audit_storage = Arc::new(crate::storage::MemoryStorage::new());
326        let audit_manager = Arc::new(crate::audit::AuditLogger::new(audit_storage));
327
328        // Create a token manager with a cryptographically random ephemeral secret.
329        // This avoids holding a well-known hardcoded secret in memory.  The real
330        // configured secret is applied during initialize().
331        // SAFETY: CSPRNG failure at initialization is terminal; the framework
332        // cannot operate without entropy.
333        let ephemeral_secret = {
334            let rng = ring::rand::SystemRandom::new();
335            let mut buf = [0u8; 32];
336            ring::rand::SecureRandom::fill(&rng, &mut buf)
337                .expect("AuthFramework fatal: system CSPRNG unavailable — the operating system cannot provide cryptographic randomness");
338            buf
339        };
340        let token_manager =
341            TokenManager::new_hmac(&ephemeral_secret, "auth-framework", "auth-framework");
342
343        let user_manager = crate::auth_modular::user_manager::UserManager::new(storage.clone());
344        let session_manager =
345            crate::auth_modular::session_manager::SessionManager::new(storage.clone());
346        let mfa_manager = crate::auth_modular::mfa::MfaManager::new(storage.clone());
347        let authorization_manager =
348            crate::auth_modular::authorization_manager::AuthorizationManager::new(
349                Arc::new(RwLock::new(PermissionChecker::new())),
350                storage.clone(),
351            );
352
353        Self {
354            config,
355            methods: HashMap::new(),
356            token_manager,
357            storage,
358            authorization_manager,
359            rate_limiter: None, // Will be set during initialization
360            monitoring_manager: Arc::new(crate::monitoring::MonitoringManager::new(
361                crate::monitoring::MonitoringConfig::default(),
362            )),
363            audit_manager,
364            #[cfg(feature = "api-server")]
365            security_manager: Arc::new(crate::api::SecurityManager::new()),
366            runtime_config: Arc::new(tokio::sync::RwLock::new(
367                crate::config::RuntimeConfig::default(),
368            )),
369            user_manager,
370            session_manager,
371            mfa_manager,
372            initialized: false,
373            storage_overridden: false,
374        }
375    }
376
377    /// Create a new authentication framework with validation.
378    ///
379    /// This method validates the configuration immediately and returns an error
380    /// if the configuration is invalid. Use this when you want early validation.
381    pub fn new_validated(config: AuthConfig) -> Result<Self> {
382        // Validate configuration - return error instead of panicking
383        config.validate().map_err(|e| {
384            AuthError::configuration(format!("Configuration validation failed: {}", e))
385        })?;
386
387        // Create token manager with proper error handling
388        let current_secret_bytes = resolve_jwt_secret_bytes(&config)?;
389
390        let mut token_manager =
391            TokenManager::new_hmac(&current_secret_bytes, "auth-framework", "auth-framework");
392
393        // Handle gracefully retained old secret for zero-downtime key rotation
394        if let Some(prev_secret) = &config.security.previous_secret_key {
395            // Initialize with previous key, then rotate to the new key
396            token_manager =
397                TokenManager::new_hmac(prev_secret.as_bytes(), "auth-framework", "auth-framework");
398            token_manager.rotate_hmac_key(&current_secret_bytes);
399        }
400
401        // Create storage backend with proper error handling
402        let storage: Arc<dyn AuthStorage> = match &config.storage {
403            #[cfg(feature = "redis-storage")]
404            crate::config::StorageConfig::Redis { url, key_prefix } => Arc::new(
405                crate::storage::RedisStorage::new(url, key_prefix).map_err(|e| {
406                    AuthError::configuration(format!("Failed to create Redis storage: {}", e))
407                })?,
408            ),
409            _ => Arc::new(MemoryStorage::new()) as Arc<dyn AuthStorage>,
410        };
411
412        // Create rate limiter if enabled
413        let rate_limiter = if config.rate_limiting.enabled {
414            Some(RateLimiter::new(
415                config.rate_limiting.max_requests,
416                config.rate_limiting.window,
417            ))
418        } else {
419            None
420        };
421
422        // Create audit manager
423        let audit_storage = Arc::new(crate::storage::MemoryStorage::new());
424        let audit_manager = Arc::new(crate::audit::AuditLogger::new(audit_storage));
425
426        let user_manager = crate::auth_modular::user_manager::UserManager::new(storage.clone());
427        let session_manager =
428            crate::auth_modular::session_manager::SessionManager::new(storage.clone());
429        let mfa_manager = crate::auth_modular::mfa::MfaManager::new(storage.clone());
430        let authorization_manager =
431            crate::auth_modular::authorization_manager::AuthorizationManager::new(
432                Arc::new(RwLock::new(PermissionChecker::new())),
433                storage.clone(),
434            );
435
436        Ok(Self {
437            config: config.clone(),
438            methods: HashMap::new(),
439            token_manager,
440            storage,
441            authorization_manager,
442            rate_limiter,
443            monitoring_manager: Arc::new(crate::monitoring::MonitoringManager::new(
444                crate::monitoring::MonitoringConfig::default(),
445            )),
446            audit_manager,
447            #[cfg(feature = "api-server")]
448            security_manager: Arc::new(crate::api::SecurityManager::new()),
449            runtime_config: Arc::new(tokio::sync::RwLock::new(
450                crate::config::RuntimeConfig::from_auth_config(&config),
451            )),
452            user_manager,
453            session_manager,
454            mfa_manager,
455            initialized: false,
456            storage_overridden: false,
457        })
458    }
459
460    /// Replace the storage backend with a custom implementation.
461    ///
462    /// This will swap the internal storage Arc so subsequent operations use
463    /// the provided storage instance. Implementations that rely on a
464    /// different concrete storage may need additional reconfiguration by the
465    /// caller.
466    pub fn replace_storage(&mut self, storage: std::sync::Arc<dyn AuthStorage>) {
467        self.storage = storage.clone();
468        self.user_manager = crate::auth_modular::user_manager::UserManager::new(storage.clone());
469        self.session_manager =
470            crate::auth_modular::session_manager::SessionManager::new(storage.clone());
471        self.mfa_manager = crate::auth_modular::mfa::MfaManager::new(storage.clone());
472        self.authorization_manager =
473            crate::auth_modular::authorization_manager::AuthorizationManager::new(
474                Arc::new(RwLock::new(PermissionChecker::new())),
475                storage,
476            );
477        self.storage_overridden = true;
478    }
479
480    /// Replace the distributed session store.
481    ///
482    /// Call this during application startup after configuring a distributed cache
483    /// (Redis, Valkey, Hazelcast, etc.) so that
484    /// [`coordinate_distributed_sessions`][Self::coordinate_distributed_sessions]
485    /// reports accurate cross-node session counts instead of `0`.
486    pub fn set_distributed_store(&mut self, store: Arc<dyn DistributedSessionStore>) {
487        self.session_manager.set_distributed_store(store);
488    }
489
490    /// Convenience constructor that creates a framework with a custom storage instance.
491    pub fn new_with_storage(config: AuthConfig, storage: std::sync::Arc<dyn AuthStorage>) -> Self {
492        let mut framework = Self::new(config);
493        framework.replace_storage(storage);
494        framework
495    }
496
497    /// Register an authentication method.
498    pub fn register_method(&mut self, name: impl Into<String>, method: AuthMethodEnum) {
499        let name = name.into();
500        info!("Registering authentication method: {}", name);
501
502        // Validate method configuration
503        if let Err(e) = method.validate_config() {
504            error!("Method '{}' configuration validation failed: {}", name, e);
505            return;
506        }
507
508        self.methods.insert(name, method);
509    }
510
511    /// Returns `Ok(())` when the framework has been initialised, or a clear
512    /// error telling the caller what to do.
513    ///
514    /// Prefer calling this at the top of every public method that touches
515    /// storage, tokens, sessions, or authorisation state.
516    fn require_initialized(&self) -> Result<()> {
517        if self.initialized {
518            Ok(())
519        } else {
520            Err(AuthError::configuration(
521                "Framework not initialized. Call `initialize().await` first, \
522                 or use `AuthFramework::builder().build().await` which initializes automatically.",
523            ))
524        }
525    }
526
527    /// Initialize the authentication framework.
528    ///
529    /// This method performs configuration validation, sets up secure components,
530    /// and prepares the framework for use. It must be called before any other operations.
531    ///
532    /// # Security Note
533    ///
534    /// This method validates JWT secrets and replaces any temporary secrets with
535    /// properly configured ones for production security.
536    pub async fn initialize(&mut self) -> Result<()> {
537        if self.initialized {
538            return Ok(());
539        }
540
541        info!("Initializing authentication framework");
542
543        // Validate configuration
544        self.config.validate().map_err(|e| {
545            AuthError::configuration(format!("Configuration validation failed: {}", e))
546        })?;
547
548        // Set up proper token manager with validated configuration
549        let token_manager = match resolve_jwt_secret_bytes(&self.config) {
550            Ok(bytes) => TokenManager::new_hmac(&bytes, "auth-framework", "auth-framework"),
551            Err(_) => {
552                if Self::is_production_environment() {
553                    return Err(AuthError::configuration(
554                        "Production deployment requires JWT_SECRET environment variable or configuration!\n\
555                         Generate a secure secret with: openssl rand -base64 32\n\
556                         Set it with: export JWT_SECRET=\"your-secret-here\"",
557                    ));
558                }
559                warn!("No JWT secret configured, using development-only default");
560                warn!("CRITICAL: Set JWT_SECRET environment variable for production!");
561                warn!("This configuration is NOT SECURE and should only be used in development!");
562                self.token_manager.clone()
563            }
564        };
565
566        // Replace token manager with properly configured one
567        self.token_manager = token_manager;
568
569        // Set up storage backend if not already configured
570        if !self.storage_overridden {
571            let storage =
572                crate::storage::factory::build_storage_backend(&self.config.storage, None).await?;
573            self.replace_storage(storage);
574            self.storage_overridden = false;
575        }
576
577        // Set up rate limiter if enabled
578        if self.config.rate_limiting.enabled {
579            self.rate_limiter = Some(RateLimiter::new(
580                self.config.rate_limiting.max_requests,
581                self.config.rate_limiting.window,
582            ));
583        }
584
585        // Initialize permission checker with default roles
586        self.authorization_manager.create_default_roles().await;
587
588        // Load any previously persisted roles and user→role assignments
589        self.authorization_manager.load_persisted_roles().await?;
590
591        // Perform any necessary setup
592        self.cleanup_expired_data().await?;
593
594        self.initialized = true;
595        info!("Authentication framework initialized successfully");
596
597        Ok(())
598    }
599
600    /// Authenticate a user with the specified method.
601    ///
602    /// `method_name` must match a previously registered authentication method
603    /// (e.g. `"password"`, `"jwt"`, `"oauth2"`).
604    ///
605    /// # Returns
606    ///
607    /// - [`AuthResult::Success`] — authentication succeeded; contains the issued token.
608    /// - [`AuthResult::MfaRequired`] — first factor passed but MFA is required.
609    /// - [`AuthResult::Failure`] — invalid credentials.
610    ///
611    /// # Example
612    ///
613    /// ```rust,no_run
614    /// # use auth_framework::prelude::*;
615    /// # use auth_framework::authentication::credentials::Credential;
616    /// # use auth_framework::auth::AuthResult;
617    /// # async fn example(auth: &AuthFramework) -> Result<(), AuthError> {
618    /// let result = auth.authenticate("password", Credential::password("alice", "S3cur3P@ss!")).await?;
619    /// match result {
620    ///     AuthResult::Success(token) => println!("Token: {}", token.access_token),
621    ///     AuthResult::MfaRequired(challenge) => println!("MFA needed: {:?}", challenge),
622    ///     AuthResult::Failure(msg) => eprintln!("Login failed: {msg}"),
623    /// }
624    /// # Ok(())
625    /// # }
626    /// ```
627    pub async fn authenticate(
628        &self,
629        method_name: &str,
630        credential: Credential,
631    ) -> Result<AuthResult> {
632        self.authenticate_with_metadata(method_name, credential, CredentialMetadata::new())
633            .await
634    }
635
636    /// Authenticate a user with the specified method and metadata.
637    pub async fn authenticate_with_metadata(
638        &self,
639        method_name: &str,
640        credential: Credential,
641        metadata: CredentialMetadata,
642    ) -> Result<AuthResult> {
643        use std::time::Instant;
644        use tokio::time::{Duration as TokioDuration, sleep};
645
646        let start_time = Instant::now();
647
648        // Record authentication request
649        self.monitoring_manager.record_auth_request().await;
650
651        self.require_initialized()?;
652
653        // Perform the authentication logic
654        let result = self
655            .authenticate_internal(method_name, credential, metadata)
656            .await;
657
658        // Ensure minimum response time to prevent timing attacks
659        let min_duration = TokioDuration::from_millis(100); // 100ms minimum
660        let elapsed = start_time.elapsed();
661        if elapsed < min_duration {
662            sleep(min_duration - elapsed).await;
663        }
664
665        // Record authentication performance
666        if let Ok(ref auth_result) = result {
667            match auth_result {
668                AuthResult::Success(token) => {
669                    self.monitoring_manager
670                        .record_auth_success(&token.user_id, elapsed)
671                        .await;
672                }
673                AuthResult::Failure(reason) => {
674                    self.monitoring_manager
675                        .record_auth_failure(None, reason)
676                        .await;
677                }
678                _ => {} // MFA required - not counted as failure
679            }
680        }
681
682        result
683    }
684
685    /// Internal authentication logic without timing protection
686    async fn authenticate_internal(
687        &self,
688        method_name: &str,
689        credential: Credential,
690        metadata: CredentialMetadata,
691    ) -> Result<AuthResult> {
692        // Check rate limiting
693        if let Some(ref rate_limiter) = self.rate_limiter {
694            let rate_key = format!(
695                "auth:{}:{}",
696                method_name,
697                metadata.client_ip.as_deref().unwrap_or("unknown")
698            );
699
700            if !rate_limiter.is_allowed(&rate_key) {
701                warn!(
702                    "Rate limit exceeded for method '{}' from IP {:?}",
703                    method_name, metadata.client_ip
704                );
705                return Err(AuthError::rate_limit("Too many authentication attempts"));
706            }
707        }
708
709        // Built-in password authentication: reads credentials from framework storage directly.
710        // This handles password auth even when no "password" method has been explicitly registered,
711        // allowing the register endpoint and login endpoint to work with the same storage backend.
712        if method_name == "password"
713            && let Credential::Password {
714                ref username,
715                ref password,
716            } = credential
717        {
718            return self
719                .authenticate_password_builtin(username, password, &metadata)
720                .await;
721        }
722
723        if method_name == "jwt" {
724            return match credential {
725                Credential::Jwt { token } | Credential::Bearer { token } => {
726                    self.authenticate_jwt_builtin(&token, &metadata, "jwt")
727                        .await
728                }
729                _ => Ok(AuthResult::Failure(
730                    "JWT authentication expects Credential::jwt or Credential::bearer".to_string(),
731                )),
732            };
733        }
734
735        if matches!(method_name, "api_key" | "api-key") {
736            return match credential {
737                Credential::ApiKey { key } => {
738                    self.authenticate_api_key_builtin(&key, &metadata, "api_key")
739                        .await
740                }
741                _ => Ok(AuthResult::Failure(
742                    "API key authentication expects Credential::api_key".to_string(),
743                )),
744            };
745        }
746
747        if method_name == "oauth2" {
748            return self
749                .authenticate_oauth2_builtin(credential, &metadata)
750                .await;
751        }
752
753        // Get the authentication method
754        let method = self.methods.get(method_name).ok_or_else(|| {
755            AuthError::auth_method(method_name, "Authentication method not found".to_string())
756        })?;
757
758        // Log authentication attempt
759        debug!(
760            "Authentication attempt with method '{}' for credential: {}",
761            method_name,
762            credential.safe_display()
763        );
764
765        // Perform authentication
766        let result = method.authenticate(credential, metadata.clone()).await?;
767
768        // Log and handle the result
769        match &result {
770            MethodResult::Success(token) => {
771                info!(
772                    "Authentication successful for user '{}' with method '{}'",
773                    token.user_id, method_name
774                );
775
776                // Store token
777                self.storage.store_token(token).await?;
778
779                // Log audit event
780                self.log_audit_event("auth_success", &token.user_id, method_name, &metadata)
781                    .await;
782
783                Ok(AuthResult::Success(token.clone()))
784            }
785
786            MethodResult::MfaRequired(challenge) => {
787                info!(
788                    "MFA required for user '{}' with method '{}'",
789                    challenge.user_id, method_name
790                );
791
792                // Store MFA challenge with resource limits
793                self.guard_and_store_mfa_challenge((**challenge).clone())
794                    .await?;
795
796                // Log audit event
797                self.log_audit_event("mfa_required", &challenge.user_id, method_name, &metadata)
798                    .await;
799
800                Ok(AuthResult::MfaRequired(challenge.clone()))
801            }
802
803            MethodResult::Failure { reason } => {
804                warn!(
805                    "Authentication failed for method '{}': {}",
806                    method_name, reason
807                );
808
809                // Log audit event
810                self.log_audit_event("auth_failure", "unknown", method_name, &metadata)
811                    .await;
812
813                Ok(AuthResult::Failure(reason.clone()))
814            }
815        }
816    }
817
818    async fn authenticate_jwt_builtin(
819        &self,
820        token: &str,
821        metadata: &CredentialMetadata,
822        auth_method: &str,
823    ) -> Result<AuthResult> {
824        if token.is_empty() {
825            return Ok(AuthResult::Failure("JWT token cannot be empty".to_string()));
826        }
827
828        match self.token_manager.validate_jwt_token(token) {
829            Ok(claims) => {
830                let token =
831                    Self::build_validated_jwt_auth_token(token, claims, metadata, auth_method);
832                Ok(AuthResult::Success(Box::new(token)))
833            }
834            Err(error) => {
835                if let Some(reason) = Self::credential_failure_reason(&error) {
836                    Ok(AuthResult::Failure(reason))
837                } else {
838                    Err(error)
839                }
840            }
841        }
842    }
843
844    async fn authenticate_api_key_builtin(
845        &self,
846        api_key: &str,
847        metadata: &CredentialMetadata,
848        auth_method: &str,
849    ) -> Result<AuthResult> {
850        if api_key.is_empty() {
851            return Ok(AuthResult::Failure("API key cannot be empty".to_string()));
852        }
853
854        match self.validate_api_key(api_key).await {
855            Ok(user) => {
856                let scopes: Vec<String> = if user.roles.is_empty() {
857                    vec!["api_user".to_string()]
858                } else {
859                    user.roles.to_vec()
860                };
861                let mut token = self
862                    .token_manager
863                    .create_auth_token(&user.id, scopes.clone(), auth_method, None)?
864                    .with_roles(user.roles)
865                    .with_scopes(scopes);
866                token.metadata.issued_ip = metadata.client_ip.clone();
867                token.metadata.user_agent = metadata.user_agent.clone();
868                Ok(AuthResult::Success(Box::new(token)))
869            }
870            Err(error) => {
871                if let Some(reason) = Self::credential_failure_reason(&error) {
872                    Ok(AuthResult::Failure(reason))
873                } else {
874                    Err(error)
875                }
876            }
877        }
878    }
879
880    async fn authenticate_oauth2_builtin(
881        &self,
882        credential: Credential,
883        metadata: &CredentialMetadata,
884    ) -> Result<AuthResult> {
885        match credential {
886            Credential::OAuth {
887                authorization_code, ..
888            } => {
889                if authorization_code.is_empty() {
890                    return Ok(AuthResult::Failure(
891                        "OAuth authorization code cannot be empty".to_string(),
892                    ));
893                }
894                Ok(AuthResult::Failure(
895                    "OAuth 2.0 authorization codes must be exchanged through an OAuth provider or server endpoint before authentication completes"
896                        .to_string(),
897                ))
898            }
899            Credential::OAuthRefresh { refresh_token } => {
900                if refresh_token.is_empty() {
901                    return Ok(AuthResult::Failure(
902                        "OAuth refresh token cannot be empty".to_string(),
903                    ));
904                }
905                Ok(AuthResult::Failure(
906                    "OAuth 2.0 refresh tokens must be exchanged through an OAuth provider or server endpoint before authentication completes"
907                        .to_string(),
908                ))
909            }
910            Credential::Jwt { token }
911            | Credential::Bearer { token }
912            | Credential::OpenIdConnect { id_token: token, .. } => {
913                self.authenticate_jwt_builtin(&token, metadata, "oauth2").await
914            }
915            _ => Ok(AuthResult::Failure(
916                "OAuth2 authentication expects Credential::oauth_code, Credential::oauth_refresh, Credential::jwt, Credential::bearer, or Credential::openid_connect"
917                    .to_string(),
918            )),
919        }
920    }
921
922    fn build_validated_jwt_auth_token(
923        raw_token: &str,
924        claims: crate::tokens::JwtClaims,
925        metadata: &CredentialMetadata,
926        auth_method: &str,
927    ) -> AuthToken {
928        let crate::tokens::JwtClaims {
929            sub,
930            iss,
931            exp,
932            iat,
933            jti,
934            scope,
935            permissions,
936            roles,
937            client_id,
938            ..
939        } = claims;
940
941        let now = chrono::Utc::now();
942        let issued_at = chrono::DateTime::<chrono::Utc>::from_timestamp(iat, 0).unwrap_or(now);
943        let expires_at = chrono::DateTime::<chrono::Utc>::from_timestamp(exp, 0)
944            .unwrap_or(now + chrono::Duration::hours(1));
945        let lifetime = (expires_at - now)
946            .to_std()
947            .unwrap_or_else(|_| Duration::from_secs(1));
948        let scopes = if scope.trim().is_empty() {
949            Vec::new()
950        } else {
951            scope.split_whitespace().map(str::to_string).collect()
952        };
953
954        let mut token = AuthToken::new(sub.clone(), raw_token.to_string(), lifetime, auth_method)
955            .with_scopes(scopes)
956            .with_permissions(permissions.unwrap_or_default())
957            .with_roles(roles.unwrap_or_default());
958        token.token_id = jti;
959        token.subject = Some(sub);
960        token.issuer = Some(iss);
961        token.issued_at = issued_at;
962        token.expires_at = expires_at;
963        token.metadata.issued_ip = metadata.client_ip.clone();
964        token.metadata.user_agent = metadata.user_agent.clone();
965        if let Some(client_id) = client_id {
966            token.client_id = Some(client_id);
967        }
968        token
969    }
970
971    fn credential_failure_reason(error: &AuthError) -> Option<String> {
972        match error {
973            AuthError::Token(_) | AuthError::Jwt(_) => Some(error.to_string()),
974            AuthError::Validation { message } => Some(message.clone()),
975            AuthError::UserNotFound => Some("User not found".to_string()),
976            _ => None,
977        }
978    }
979
980    /// Built-in password authentication against framework storage.
981    async fn authenticate_password_builtin(
982        &self,
983        username: &str,
984        password: &str,
985        metadata: &CredentialMetadata,
986    ) -> Result<AuthResult> {
987        use crate::auth_modular::user_manager::CredentialCheckResult;
988
989        if username.is_empty() || password.is_empty() {
990            return Ok(AuthResult::Failure(
991                "Username or password cannot be empty".to_string(),
992            ));
993        }
994
995        match self
996            .user_manager
997            .verify_login_credentials(username, password)
998            .await?
999        {
1000            None => {
1001                self.log_audit_event("auth_failure", "unknown", "password", metadata)
1002                    .await;
1003                Ok(AuthResult::Failure(
1004                    "Invalid username or password".to_string(),
1005                ))
1006            }
1007            Some(CredentialCheckResult {
1008                ref user_id,
1009                mfa_enabled: true,
1010            }) => {
1011                let now = chrono::Utc::now();
1012                let challenge = MfaChallenge {
1013                    id: crate::utils::string::generate_id(Some("mfa")),
1014                    mfa_type: crate::methods::MfaType::MultiMethod,
1015                    user_id: user_id.clone(),
1016                    created_at: now,
1017                    expires_at: now + chrono::Duration::minutes(5),
1018                    attempts: 0,
1019                    max_attempts: 5,
1020                    code_hash: None,
1021                    message: Some(
1022                        "Provide your current TOTP code or a backup code to complete login"
1023                            .to_string(),
1024                    ),
1025                    data: HashMap::new(),
1026                };
1027                self.guard_and_store_mfa_challenge(challenge.clone())
1028                    .await?;
1029                self.log_audit_event("mfa_required", user_id, "password", metadata)
1030                    .await;
1031                info!(
1032                    "Built-in password authentication requires MFA for user: {}",
1033                    username
1034                );
1035                Ok(AuthResult::MfaRequired(Box::new(challenge)))
1036            }
1037            Some(CredentialCheckResult {
1038                ref user_id,
1039                mfa_enabled: false,
1040            }) => {
1041                let token = self
1042                    .mint_and_store_token(
1043                        user_id,
1044                        vec!["read".to_string(), "write".to_string()],
1045                        "password",
1046                        None,
1047                    )
1048                    .await?;
1049                self.monitoring_manager.record_auth_request().await;
1050                self.log_audit_event("auth_success", user_id, "password", metadata)
1051                    .await;
1052                info!(
1053                    "Built-in password authentication successful for user: {}",
1054                    username
1055                );
1056                Ok(AuthResult::Success(Box::new(token)))
1057            }
1058        }
1059    }
1060
1061    /// Complete multi-factor authentication.
1062    pub async fn complete_mfa(&self, challenge: MfaChallenge, mfa_code: &str) -> Result<AuthToken> {
1063        debug!("Completing MFA for challenge '{}'", challenge.id);
1064
1065        let stored_challenge = self
1066            .mfa_manager
1067            .get_challenge(&challenge.id)
1068            .await?
1069            .ok_or(MfaError::ChallengeExpired)?;
1070
1071        if stored_challenge.is_expired() {
1072            self.mfa_manager.remove_challenge(&challenge.id).await?;
1073            return Err(MfaError::ChallengeExpired.into());
1074        }
1075
1076        if !self.verify_mfa_code(&stored_challenge, mfa_code).await? {
1077            return Err(MfaError::InvalidCode.into());
1078        }
1079
1080        self.mfa_manager.remove_challenge(&challenge.id).await?;
1081
1082        let scopes = self
1083            .user_manager
1084            .get_user_roles(&challenge.user_id)
1085            .await
1086            .unwrap_or_else(|_| vec!["user".to_string()]);
1087
1088        let token = self
1089            .mint_and_store_token(&challenge.user_id, scopes, "mfa", None)
1090            .await?;
1091
1092        info!(
1093            "MFA completed successfully for user '{}'",
1094            challenge.user_id
1095        );
1096        Ok(token)
1097    }
1098
1099    /// Complete MFA using a previously issued challenge ID.
1100    pub async fn complete_mfa_by_id(
1101        &self,
1102        challenge_id: &str,
1103        mfa_code: &str,
1104    ) -> Result<AuthToken> {
1105        let challenge = self
1106            .mfa_manager
1107            .get_challenge(challenge_id)
1108            .await?
1109            .ok_or(MfaError::ChallengeExpired)?;
1110
1111        self.complete_mfa(challenge, mfa_code).await
1112    }
1113
1114    /// Validate a token.
1115    pub async fn validate_token(&self, token: &AuthToken) -> Result<bool> {
1116        self.require_initialized()?;
1117        let valid = token.is_valid()
1118            && self.token_manager.validate_auth_token(token).is_ok()
1119            && self.touch_stored_token(token).await?;
1120        self.monitoring_manager.record_token_validation(valid).await;
1121        Ok(valid)
1122    }
1123
1124    async fn touch_stored_token(&self, token: &AuthToken) -> Result<bool> {
1125        let Some(mut stored) = self.storage.get_token(&token.token_id).await? else {
1126            return Ok(false);
1127        };
1128        stored.mark_used();
1129        self.storage.update_token(&stored).await?;
1130        Ok(true)
1131    }
1132
1133    /// Get user information from a token.
1134    pub async fn get_user_info(&self, token: &AuthToken) -> Result<UserInfo> {
1135        if !self.validate_token(token).await? {
1136            return Err(AuthError::auth_method("token", "Invalid token".to_string()));
1137        }
1138
1139        let token_info = self.token_manager.extract_token_info(&token.access_token)?;
1140
1141        // Fetch authoritative user state (active flag, current roles) from storage.
1142        // Fall back to token claims if the user record is not found.
1143        match self.user_manager.get_user_info(&token_info.user_id).await {
1144            Ok(mut info) => {
1145                // Overlay any token-specific attributes on top of the stored profile.
1146                if !token_info.attributes.is_empty() {
1147                    let string_attrs: HashMap<String, String> = token_info
1148                        .attributes
1149                        .into_iter()
1150                        .map(|(k, v)| {
1151                            (
1152                                k,
1153                                v.as_str()
1154                                    .map(|s| s.to_string())
1155                                    .unwrap_or_else(|| v.to_string()),
1156                            )
1157                        })
1158                        .collect();
1159                    info.attributes = string_attrs.into();
1160                }
1161                Ok(info)
1162            }
1163            Err(_) => {
1164                let string_attrs: HashMap<String, String> = token_info
1165                    .attributes
1166                    .into_iter()
1167                    .map(|(k, v)| {
1168                        (
1169                            k,
1170                            v.as_str()
1171                                .map(|s| s.to_string())
1172                                .unwrap_or_else(|| v.to_string()),
1173                        )
1174                    })
1175                    .collect();
1176                Ok(UserInfo {
1177                    id: token_info.user_id,
1178                    username: token_info.username.unwrap_or_else(|| "unknown".to_string()),
1179                    email: token_info.email,
1180                    name: token_info.name,
1181                    roles: token_info.roles.into(),
1182                    active: false,
1183                    email_verified: false,
1184                    attributes: string_attrs.into(),
1185                })
1186            }
1187        }
1188    }
1189
1190    /// Check if a token has permission to perform an action on a resource.
1191    ///
1192    /// This method validates the token and checks if the authenticated user
1193    /// has the required permission for the specified action on the given resource.
1194    ///
1195    /// # Parameters
1196    /// - `token`: The authentication token to validate and check permissions for
1197    /// - `action`: The action being requested (e.g., "read", "write", "delete")
1198    /// - `resource`: The resource being accessed (e.g., "documents", "users", "reports/123")
1199    ///
1200    /// # Returns
1201    /// Returns `true` if the token is valid and the user has the required permission,
1202    /// `false` if the token is invalid or the user lacks permission.
1203    ///
1204    /// # Example
1205    /// ```rust,no_run
1206    /// # use auth_framework::prelude::*;
1207    /// # async fn example(auth: &AuthFramework, token: &AuthToken) -> Result<(), AuthError> {
1208    /// if auth.check_permission(token, "read", "documents").await? {
1209    ///     println!("User can read documents");
1210    /// } else {
1211    ///     println!("Access denied");
1212    /// }
1213    /// # Ok(())
1214    /// # }
1215    /// ```
1216    pub async fn check_permission(
1217        &self,
1218        token: &AuthToken,
1219        action: &str,
1220        resource: &str,
1221    ) -> Result<bool> {
1222        if !self.validate_token(token).await? {
1223            return Ok(false);
1224        }
1225        self.authorization_manager
1226            .check_token_permission(token, action, resource)
1227            .await
1228    }
1229
1230    /// Refresh a token.
1231    pub async fn refresh_token(&self, token: &AuthToken) -> Result<AuthToken> {
1232        self.require_initialized()?;
1233        debug!("Refreshing token for user '{}'", token.user_id);
1234
1235        // Check if the auth method supports refresh
1236        if let Some(method) = self.methods.get(&token.auth_method)
1237            && method.supports_refresh()
1238            && let Some(ref refresh_token) = token.refresh_token
1239        {
1240            let new_token = method.refresh_token(refresh_token.to_string()).await?;
1241            self.storage.store_token(&new_token).await?;
1242            return Ok(new_token);
1243        }
1244
1245        // Fallback to creating a new token with the same properties
1246        let new_token = self.token_manager.refresh_token(token)?;
1247        self.storage.store_token(&new_token).await?;
1248
1249        info!("Token refreshed for user '{}'", token.user_id);
1250
1251        Ok(new_token)
1252    }
1253
1254    /// Revoke a token.
1255    pub async fn revoke_token(&self, token: &AuthToken) -> Result<()> {
1256        self.require_initialized()?;
1257        debug!("Revoking token for user '{}'", token.user_id);
1258
1259        // Mark token as revoked
1260        let mut revoked_token = token.clone();
1261        revoked_token.revoke(Some("Manual revocation".to_string()));
1262
1263        // Update in storage
1264        self.storage.update_token(&revoked_token).await?;
1265
1266        info!("Token revoked for user '{}'", token.user_id);
1267
1268        Ok(())
1269    }
1270
1271    /// Create a new API key for a user.
1272    pub async fn create_api_key(
1273        &self,
1274        user_id: &str,
1275        expires_in: Option<Duration>,
1276    ) -> Result<String> {
1277        self.require_initialized()?;
1278        self.user_manager.create_api_key(user_id, expires_in).await
1279    }
1280
1281    /// Validate an API key and return user information.
1282    pub async fn validate_api_key(&self, api_key: &str) -> Result<UserInfo> {
1283        self.require_initialized()?;
1284        self.user_manager.validate_api_key(api_key).await
1285    }
1286
1287    /// Revoke an API key.
1288    pub async fn revoke_api_key(&self, api_key: &str) -> Result<()> {
1289        self.require_initialized()?;
1290        self.user_manager.revoke_api_key(api_key).await
1291    }
1292
1293    /// Create a new session.
1294    pub async fn create_session(
1295        &self,
1296        user_id: &str,
1297        expires_in: Duration,
1298        ip_address: Option<String>,
1299        user_agent: Option<String>,
1300    ) -> Result<String> {
1301        self.require_initialized()?;
1302        let (session_id, new_total) = self
1303            .session_manager
1304            .create_session_limited(user_id, expires_in, ip_address, user_agent)
1305            .await?;
1306        self.monitoring_manager
1307            .update_session_count(new_total)
1308            .await;
1309        Ok(session_id)
1310    }
1311
1312    /// Create a new session using a [`SessionCreateRequest`] for better readability.
1313    ///
1314    /// Prefer [`create_session_with_request`](Self::create_session_with_request)
1315    /// with a [`SessionCreateRequest`] for better readability when using optional fields.
1316    ///
1317    /// # Example
1318    ///
1319    /// ```rust,no_run
1320    /// # use auth_framework::{prelude::*, auth_operations::SessionCreateRequest};
1321    /// # use std::time::Duration;
1322    /// # async fn example(auth: &AuthFramework) -> Result<(), auth_framework::errors::AuthError> {
1323    /// let session_id = auth.create_session_with_request(
1324    ///     SessionCreateRequest::new("user_123", Duration::from_secs(3600))
1325    ///         .ip_address("192.168.1.1")
1326    ///         .user_agent("MyApp/1.0")
1327    /// ).await?;
1328    /// # Ok(())
1329    /// # }
1330    /// ```
1331    pub async fn create_session_with_request(&self, req: SessionCreateRequest) -> Result<String> {
1332        self.create_session(
1333            req.get_user_id(),
1334            req.get_expires_in(),
1335            req.get_ip_address().map(|s| s.to_string()),
1336            req.get_user_agent().map(|s| s.to_string()),
1337        )
1338        .await
1339    }
1340
1341    /// Get session information.
1342    pub async fn get_session(&self, session_id: &str) -> Result<Option<SessionData>> {
1343        self.require_initialized()?;
1344        self.session_manager.get_session(session_id).await
1345    }
1346
1347    /// Delete a session.
1348    pub async fn delete_session(&self, session_id: &str) -> Result<()> {
1349        self.require_initialized()?;
1350        self.session_manager.delete_session(session_id).await?;
1351
1352        let remaining = self
1353            .session_manager
1354            .count_active_sessions()
1355            .await
1356            .unwrap_or(0);
1357        self.monitoring_manager
1358            .update_session_count(remaining)
1359            .await;
1360
1361        Ok(())
1362    }
1363
1364    /// Get all tokens for a user.
1365    pub async fn list_user_tokens(&self, user_id: &str) -> Result<Vec<AuthToken>> {
1366        self.require_initialized()?;
1367        self.storage.list_user_tokens(user_id).await
1368    }
1369
1370    /// Clean up expired data.
1371    pub async fn cleanup_expired_data(&self) -> Result<()> {
1372        debug!("Cleaning up expired data");
1373
1374        // Clean up storage
1375        self.storage.cleanup_expired().await?;
1376
1377        // Clean up MFA challenges via mfa manager
1378        self.mfa_manager.cleanup_expired_challenges().await?;
1379
1380        // Clean up sessions via session manager
1381        self.session_manager.cleanup_expired_sessions().await?;
1382
1383        // Clean up rate limiter
1384        if let Some(ref rate_limiter) = self.rate_limiter {
1385            let _ = rate_limiter.cleanup().ok();
1386        }
1387
1388        Ok(())
1389    }
1390
1391    /// Detect if the process is running in a production environment by inspecting
1392    /// well-known environment variables and container indicators.
1393    fn is_production_environment() -> bool {
1394        if let Ok(env) = std::env::var("ENVIRONMENT")
1395            && (env.to_lowercase() == "production" || env.to_lowercase() == "prod")
1396        {
1397            return true;
1398        }
1399        if let Ok(env) = std::env::var("ENV")
1400            && (env.to_lowercase() == "production" || env.to_lowercase() == "prod")
1401        {
1402            return true;
1403        }
1404        if let Ok(env) = std::env::var("NODE_ENV")
1405            && env.to_lowercase() == "production"
1406        {
1407            return true;
1408        }
1409        if let Ok(env) = std::env::var("RUST_ENV")
1410            && env.to_lowercase() == "production"
1411        {
1412            return true;
1413        }
1414        std::env::var("KUBERNETES_SERVICE_HOST").is_ok()
1415            || std::env::var("DOCKER_CONTAINER").is_ok()
1416    }
1417
1418    /// Get authentication framework statistics.
1419    pub async fn get_stats(&self) -> Result<AuthStats> {
1420        let mut stats = AuthStats::default();
1421
1422        if let Err(e) = self.storage.cleanup_expired().await {
1423            warn!("Failed to cleanup expired data: {}", e);
1424        }
1425        if let Some(rate_limiter) = &self.rate_limiter {
1426            let _ = rate_limiter.cleanup().ok();
1427        }
1428
1429        let active_sessions = self
1430            .session_manager
1431            .count_active_sessions()
1432            .await
1433            .unwrap_or(0) as u32;
1434
1435        stats.registered_methods = self.methods.keys().cloned().collect();
1436        stats.active_sessions = active_sessions as u64;
1437        stats.active_mfa_challenges = self.mfa_manager.get_active_challenge_count().await as u64;
1438        // Use monitoring counters for accurate cumulative tracking
1439        let perf = self.monitoring_manager.get_performance_metrics();
1440        stats.tokens_issued = perf.get("token_creations").copied().unwrap_or(0);
1441        stats.auth_attempts = perf.get("auth_successes").copied().unwrap_or(0)
1442            + perf.get("auth_failures").copied().unwrap_or(0);
1443
1444        Ok(stats)
1445    }
1446
1447    /// Returns a reference to the underlying [`TokenManager`].
1448    ///
1449    /// Useful for advanced token operations not exposed by the
1450    /// [`TokenOperations`] facade.
1451    pub fn token_manager(&self) -> &TokenManager {
1452        &self.token_manager
1453    }
1454
1455    /// Validates a username against the configured format rules.
1456    ///
1457    /// Returns `Ok(true)` when the name is acceptable, or an error describing
1458    /// the specific rule that was violated (length, characters, etc.).
1459    ///
1460    /// # Errors
1461    ///
1462    /// Returns [`AuthError`] if the username is empty, too long, or contains
1463    /// forbidden characters per the active [`SecurityConfig`].
1464    pub async fn validate_username(&self, username: &str) -> Result<bool> {
1465        self.user_manager.validate_username(username).await
1466    }
1467
1468    /// Validates a display name against the configured format rules.
1469    ///
1470    /// # Errors
1471    ///
1472    /// Returns [`AuthError`] if the display name is empty or exceeds the
1473    /// configured maximum length.
1474    pub async fn validate_display_name(&self, display_name: &str) -> Result<bool> {
1475        self.user_manager.validate_display_name(display_name).await
1476    }
1477
1478    /// Checks a password against the active security policy.
1479    ///
1480    /// Validates minimum length, character-class requirements, and (optionally)
1481    /// checks against known-breached password lists.
1482    ///
1483    /// # Errors
1484    ///
1485    /// Returns [`AuthError`] describing which policy rule the password violates.
1486    pub async fn validate_password_strength(&self, password: &str) -> Result<bool> {
1487        self.user_manager.validate_password_strength(password).await
1488    }
1489
1490    /// Validates arbitrary user input against common injection patterns.
1491    ///
1492    /// Checks for SQL injection, XSS, and command injection markers.
1493    /// Returns `Ok(true)` when the input is safe.
1494    pub async fn validate_user_input(&self, input: &str) -> Result<bool> {
1495        Ok(crate::utils::validation::validate_user_input(input))
1496    }
1497
1498    /// Creates an authentication token directly.
1499    ///
1500    /// This is a low-level API intended for **testing, migration tools, and
1501    /// administrative tasks**. In production, tokens should be created through
1502    /// [`authenticate`](Self::authenticate) instead.
1503    ///
1504    /// # Parameters
1505    ///
1506    /// * `user_id`     — the subject the token is issued to.
1507    /// * `scopes`      — OAuth-style scopes (accepts `Vec<String>`, `Scopes`, or `&[&str]`).
1508    /// * `method_name` — the auth method to record (must be registered).
1509    /// * `lifetime`    — override the default token TTL; `None` uses the
1510    ///                   framework-configured default.
1511    ///
1512    /// # Errors
1513    ///
1514    /// * [`AuthError::AuthMethod`] if `method_name` is not registered.
1515    /// * [`AuthError::RateLimit`] if the user already holds the maximum number
1516    ///   of active tokens.
1517    pub async fn create_auth_token(
1518        &self,
1519        user_id: impl Into<String>,
1520        scopes: impl Into<crate::types::Scopes>,
1521        method_name: impl Into<String>,
1522        lifetime: Option<Duration>,
1523    ) -> Result<AuthToken> {
1524        let method_name = method_name.into();
1525        let user_id = user_id.into();
1526        let scopes: crate::types::Scopes = scopes.into();
1527
1528        // Validate the method exists and is correctly configured
1529        let auth_method = self
1530            .methods
1531            .get(&method_name)
1532            .ok_or_else(|| AuthError::auth_method(&method_name, "Method not found"))?;
1533        auth_method.validate_config()?;
1534
1535        // ENTERPRISE SECURITY: Check token limits to prevent resource exhaustion
1536        const MAX_TOKENS_PER_USER: usize = 100;
1537        let user_tokens = self.storage.list_user_tokens(&user_id).await?;
1538        if user_tokens.len() >= MAX_TOKENS_PER_USER {
1539            warn!(
1540                "User '{}' has reached maximum tokens ({})",
1541                user_id, MAX_TOKENS_PER_USER
1542            );
1543            return Err(AuthError::rate_limit(
1544                "Maximum tokens per user exceeded. Please revoke unused tokens.",
1545            ));
1546        }
1547
1548        let token = self
1549            .mint_and_store_token(&user_id, scopes, &method_name, lifetime)
1550            .await?;
1551        self.monitoring_manager
1552            .record_token_creation(&method_name)
1553            .await;
1554        Ok(token)
1555    }
1556
1557    /// Initiates an SMS-based MFA challenge for `user_id`.
1558    ///
1559    /// Sends a one-time code via the configured SMS provider and returns a
1560    /// challenge ID that must be passed to [`verify_sms_code`](Self::verify_sms_code).
1561    ///
1562    /// # Errors
1563    ///
1564    /// Returns [`AuthError`] if no phone number is registered or the SMS
1565    /// provider fails to deliver.
1566    pub async fn initiate_sms_challenge(&self, user_id: &str) -> Result<String> {
1567        self.mfa_manager.sms.initiate_challenge(user_id).await
1568    }
1569
1570    /// Verifies an SMS challenge code previously issued by
1571    /// [`initiate_sms_challenge`](Self::initiate_sms_challenge).
1572    ///
1573    /// # Errors
1574    ///
1575    /// Returns [`AuthError`] if the challenge has expired or if the code is
1576    /// invalid.
1577    pub async fn verify_sms_code(&self, challenge_id: &str, code: &str) -> Result<bool> {
1578        self.mfa_manager.sms.verify_code(challenge_id, code).await
1579    }
1580
1581    /// Registers an email address for email-based MFA for `user_id`.
1582    ///
1583    /// # Errors
1584    ///
1585    /// Returns [`AuthError`] if the email format is invalid or the user does
1586    /// not exist.
1587    pub async fn register_email(&self, user_id: &str, email: &str) -> Result<()> {
1588        self.mfa_manager.email.register_email(user_id, email).await
1589    }
1590
1591    /// Generates a new TOTP secret and stores it for `user_id`.
1592    ///
1593    /// The returned string is a Base32-encoded secret suitable for importing
1594    /// into authenticator apps. Pair with
1595    /// [`generate_totp_qr_code`](Self::generate_totp_qr_code) for a scan-ready
1596    /// URI.
1597    ///
1598    /// # Errors
1599    ///
1600    /// Returns [`AuthError`] if secret generation or storage fails.
1601    pub async fn generate_totp_secret(&self, user_id: &str) -> Result<String> {
1602        self.mfa_manager.totp.generate_secret(user_id).await
1603    }
1604
1605    /// Generates an `otpauth://` URI suitable for rendering as a QR code.
1606    ///
1607    /// # Parameters
1608    ///
1609    /// * `user_id`  — identifies the user in the authenticator label.
1610    /// * `app_name` — the issuer name shown in the authenticator app.
1611    /// * `secret`   — the Base32 TOTP secret from [`generate_totp_secret`](Self::generate_totp_secret).
1612    pub async fn generate_totp_qr_code(
1613        &self,
1614        user_id: &str,
1615        app_name: &str,
1616        secret: &str,
1617    ) -> Result<String> {
1618        self.mfa_manager
1619            .totp
1620            .generate_qr_code(user_id, app_name, secret)
1621            .await
1622    }
1623
1624    /// Generates the current TOTP code for the given Base32 `secret`.
1625    ///
1626    /// Primarily useful for testing; in production the *user* generates the
1627    /// code on their device.
1628    pub async fn generate_totp_code(&self, secret: &str) -> Result<String> {
1629        self.mfa_manager.totp.generate_code(secret).await
1630    }
1631
1632    /// Generates a TOTP code for the given `secret` and optional time window.
1633    ///
1634    /// When `time_window` is `None`, the current 30-second window is used.
1635    pub async fn generate_totp_code_for_window(
1636        &self,
1637        secret: &str,
1638        time_window: Option<u64>,
1639    ) -> Result<String> {
1640        self.mfa_manager
1641            .totp
1642            .generate_code_for_window(secret, time_window)
1643            .await
1644    }
1645
1646    /// Verifies a TOTP code against the stored secret for `user_id`.
1647    ///
1648    /// Applies a configurable clock-skew window (default: ±1 step).
1649    ///
1650    /// # Errors
1651    ///
1652    /// Returns [`AuthError`] if no TOTP secret is registered for the user.
1653    pub async fn verify_totp_code(&self, user_id: &str, code: &str) -> Result<bool> {
1654        self.mfa_manager.totp.verify_code(user_id, code).await
1655    }
1656
1657    /// Checks whether the given IP address is within the configured rate limit.
1658    ///
1659    /// Returns `Ok(true)` if the request is allowed, or an
1660    /// [`AuthError::RateLimit`] if the caller should be throttled.
1661    pub async fn check_ip_rate_limit(&self, ip: &str) -> Result<bool> {
1662        debug!("Checking IP rate limit for '{}'", ip);
1663        let Some(ref rate_limiter) = self.rate_limiter else {
1664            return Ok(true);
1665        };
1666        if !rate_limiter.is_allowed(&format!("ip:{}", ip)) {
1667            warn!("Rate limit exceeded for IP: {}", ip);
1668            return Err(AuthError::rate_limit(format!(
1669                "Too many requests from IP {}. Please try again later.",
1670                ip
1671            )));
1672        }
1673        Ok(true)
1674    }
1675
1676    /// Return security metrics for monitoring dashboards.
1677    ///
1678    /// Keys include `active_sessions`, `total_tokens`, `failed_attempts`,
1679    /// `successful_attempts`, and `expired_tokens`.
1680    pub async fn get_security_metrics(&self) -> Result<std::collections::HashMap<String, u64>> {
1681        debug!("Getting security metrics");
1682        let mut metrics = std::collections::HashMap::new();
1683        let total_active_sessions = self
1684            .session_manager
1685            .count_active_sessions()
1686            .await
1687            .unwrap_or(0);
1688        metrics.insert("active_sessions".to_string(), total_active_sessions);
1689        metrics.insert("total_tokens".to_string(), total_active_sessions);
1690        metrics.insert(
1691            "failed_attempts".to_string(),
1692            self.audit_manager
1693                .get_failed_login_count_24h()
1694                .await
1695                .unwrap_or(0),
1696        );
1697        metrics.insert(
1698            "successful_attempts".to_string(),
1699            self.audit_manager
1700                .get_successful_login_count_24h()
1701                .await
1702                .unwrap_or(0),
1703        );
1704        metrics.insert("expired_tokens".to_string(), 0u64);
1705        Ok(metrics)
1706    }
1707
1708    /// Registers a phone number for SMS-based MFA.
1709    ///
1710    /// # Errors
1711    ///
1712    /// Returns [`AuthError`] if the phone number format is invalid.
1713    pub async fn register_phone_number(&self, user_id: &str, phone_number: &str) -> Result<()> {
1714        self.mfa_manager
1715            .sms
1716            .register_phone_number(user_id, phone_number)
1717            .await
1718    }
1719
1720    /// Generate `count` one-time backup codes for the given user.
1721    ///
1722    /// Codes are persisted server-side (hashed); plaintext codes are returned
1723    /// to the caller for display to the user.
1724    pub async fn generate_backup_codes(&self, user_id: &str, count: usize) -> Result<Vec<String>> {
1725        self.mfa_manager
1726            .backup_codes
1727            .generate_codes(user_id, count)
1728            .await
1729    }
1730    /// Grants an authorization permission to a user.
1731    ///
1732    /// # Parameters
1733    ///
1734    /// * `user_id`  — the user receiving the permission.
1735    /// * `action`   — the action being allowed (e.g. `"read"`, `"write"`).
1736    /// * `resource` — the resource scope (e.g. `"documents"`, `"users:*"`).
1737    ///
1738    /// # Errors
1739    ///
1740    /// Returns [`AuthError`] if the user does not exist or storage fails.
1741    pub async fn grant_permission(
1742        &self,
1743        user_id: &str,
1744        action: &str,
1745        resource: &str,
1746    ) -> Result<()> {
1747        self.authorization_manager
1748            .grant_permission(user_id, action, resource)
1749            .await
1750    }
1751
1752    /// Initiates an email-based MFA challenge for `user_id`.
1753    ///
1754    /// Sends a one-time code to the registered email address and returns a
1755    /// challenge ID.
1756    ///
1757    /// # Errors
1758    ///
1759    /// Returns [`AuthError`] if no email is registered for the user or
1760    /// delivery fails.
1761    pub async fn initiate_email_challenge(&self, user_id: &str) -> Result<String> {
1762        self.mfa_manager.email.initiate_challenge(user_id).await
1763    }
1764
1765    /// Returns a cloned handle to the storage backend.
1766    ///
1767    /// Useful when you need to pass storage to another component or run
1768    /// direct queries outside the framework's managed API.
1769    pub fn storage(&self) -> Arc<dyn AuthStorage> {
1770        self.storage.clone()
1771    }
1772
1773    /// Returns a reference to the active framework configuration.
1774    pub fn config(&self) -> &AuthConfig {
1775        &self.config
1776    }
1777
1778    /// Reset runtime authorization state back to the default roles.
1779    pub async fn reset_authorization_runtime(&self) {
1780        self.authorization_manager.reset_runtime_state().await;
1781    }
1782
1783    /// Register a new user with username, email, and password.
1784    ///
1785    /// The password is hashed with the configured algorithm (default: Argon2)
1786    /// before storage.  Returns the generated user ID on success.
1787    ///
1788    /// # Errors
1789    ///
1790    /// Returns [`AuthError`] if:
1791    /// - The username or email is already taken
1792    /// - The password does not meet the configured complexity requirements
1793    /// - The storage backend is unavailable
1794    ///
1795    /// # Example
1796    ///
1797    /// ```rust,no_run
1798    /// # use auth_framework::prelude::*;
1799    /// # async fn example(auth: &AuthFramework) -> Result<(), AuthError> {
1800    /// let user_id = auth.users().register("alice", "alice@example.com", "S3cur3P@ss!").await?;
1801    /// println!("Created user: {user_id}");
1802    /// # Ok(())
1803    /// # }
1804    /// ```
1805    pub async fn register_user(
1806        &self,
1807        username: &str,
1808        email: &str,
1809        password: &str,
1810    ) -> Result<String> {
1811        self.require_initialized()?;
1812        self.user_manager
1813            .register_user(username, email, password)
1814            .await
1815    }
1816
1817    /// List users from the canonical user index with optional filtering and pagination.
1818    ///
1819    /// This method provides paginated access to the user directory with optional
1820    /// filtering by active status.
1821    ///
1822    /// # Parameters
1823    /// - `limit`: Maximum number of users to return (None for no limit)
1824    /// - `offset`: Number of users to skip for pagination (None for start from beginning)
1825    /// - `active_only`: If true, only return active users; if false, return all users
1826    ///
1827    /// # Returns
1828    /// Returns a vector of [`UserInfo`] structs containing user details.
1829    ///
1830    /// # Example
1831    /// ```rust,no_run
1832    /// # use auth_framework::prelude::*;
1833    /// # async fn example(auth: &AuthFramework) -> Result<(), AuthError> {
1834    /// // Get first 10 active users
1835    /// let users = auth.list_users(Some(10), None, true).await?;
1836    /// println!("Found {} active users", users.len());
1837    ///
1838    /// // Get all users (active and inactive)
1839    /// let all_users = auth.list_users(None, None, false).await?;
1840    /// # Ok(())
1841    /// # }
1842    /// ```
1843    #[deprecated(
1844        since = "0.6.0",
1845        note = "use `list_users_with_query(UserListQuery::new().limit(n).active_only())` instead"
1846    )]
1847    pub async fn list_users(
1848        &self,
1849        limit: Option<usize>,
1850        offset: Option<usize>,
1851        active_only: bool,
1852    ) -> Result<Vec<UserInfo>> {
1853        self.require_initialized()?;
1854        self.user_manager
1855            .list_users(limit, offset, active_only)
1856            .await
1857    }
1858
1859    /// List users using a [`UserListQuery`] for better readability.
1860    ///
1861    /// Prefer [`list_users_with_query`](Self::list_users_with_query)
1862    /// with a [`UserListQuery`] for better readability when using pagination or filtering.
1863    ///
1864    /// # Example
1865    ///
1866    /// ```rust,no_run
1867    /// # use auth_framework::{prelude::*, auth_operations::UserListQuery};
1868    /// # async fn example(auth: &AuthFramework) -> Result<(), auth_framework::errors::AuthError> {
1869    /// let users = auth.list_users_with_query(
1870    ///     UserListQuery::new()
1871    ///         .limit(50)
1872    ///         .active_only()
1873    /// ).await?;
1874    /// # Ok(())
1875    /// # }
1876    /// ```
1877    pub async fn list_users_with_query(&self, query: UserListQuery) -> Result<Vec<UserInfo>> {
1878        self.require_initialized()?;
1879        self.user_manager
1880            .list_users(
1881                query.get_limit(),
1882                query.get_offset(),
1883                query.get_active_only(),
1884            )
1885            .await
1886    }
1887
1888    /// Get user information by canonical user ID.
1889    pub async fn get_user_record(&self, user_id: &str) -> Result<UserInfo> {
1890        self.require_initialized()?;
1891        self.user_manager.get_user_info(user_id).await
1892    }
1893
1894    /// Update the roles assigned to a user.
1895    pub async fn update_user_roles(&self, user_id: &str, roles: &[String]) -> Result<()> {
1896        self.require_initialized()?;
1897        self.user_manager.update_user_roles(user_id, roles).await
1898    }
1899
1900    /// Set a user's active / deactivated status.
1901    pub async fn set_user_active(&self, user_id: &str, active: bool) -> Result<()> {
1902        self.require_initialized()?;
1903        self.user_manager.set_user_active(user_id, active).await
1904    }
1905
1906    /// Update a user's email address.
1907    pub async fn update_user_email(&self, user_id: &str, email: &str) -> Result<()> {
1908        self.require_initialized()?;
1909        self.user_manager.update_user_email(user_id, email).await
1910    }
1911
1912    /// Verify a user's password by user_id against the stored bcrypt hash.
1913    pub async fn verify_user_password(&self, user_id: &str, password: &str) -> Result<bool> {
1914        self.require_initialized()?;
1915        self.user_manager
1916            .verify_user_password(user_id, password)
1917            .await
1918    }
1919
1920    /// Look up a user's username by their user_id.
1921    pub async fn get_username_by_id(&self, user_id: &str) -> Result<String> {
1922        self.user_manager.get_username_by_id(user_id).await
1923    }
1924
1925    /// Check if a username exists.
1926    pub async fn username_exists(&self, username: &str) -> Result<bool> {
1927        self.user_manager.username_exists(username).await
1928    }
1929
1930    /// Check if an email exists.
1931    pub async fn email_exists(&self, email: &str) -> Result<bool> {
1932        self.user_manager.email_exists(email).await
1933    }
1934
1935    /// Get user data by username.
1936    pub async fn get_user_by_username(
1937        &self,
1938        username: &str,
1939    ) -> Result<HashMap<String, serde_json::Value>> {
1940        self.user_manager.get_user_by_username(username).await
1941    }
1942
1943    /// Update user password.
1944    pub async fn update_user_password(&self, username: &str, new_password: &str) -> Result<()> {
1945        self.require_initialized()?;
1946        self.user_manager
1947            .update_user_password(username, new_password)
1948            .await
1949    }
1950
1951    /// Update user password by canonical user ID.
1952    pub async fn update_user_password_by_id(
1953        &self,
1954        user_id: &str,
1955        new_password: &str,
1956    ) -> Result<()> {
1957        self.require_initialized()?;
1958        self.user_manager
1959            .update_user_password_by_id(user_id, new_password)
1960            .await
1961    }
1962
1963    /// Delete a user by username.
1964    pub async fn delete_user(&self, username: &str) -> Result<()> {
1965        self.require_initialized()?;
1966        self.user_manager.delete_user(username).await
1967    }
1968
1969    /// Delete a user by canonical user ID.
1970    pub async fn delete_user_by_id(&self, user_id: &str) -> Result<()> {
1971        self.require_initialized()?;
1972        self.user_manager.delete_user_by_id(user_id).await
1973    }
1974
1975    /// Verify MFA code with proper challenge validation.
1976    async fn verify_mfa_code(&self, challenge: &MfaChallenge, code: &str) -> Result<bool> {
1977        self.mfa_manager
1978            .verify_challenge_code(challenge, code)
1979            .await
1980    }
1981
1982    /// Log an audit event via tracing, subject to per-event-type config guards.
1983    async fn log_audit_event(
1984        &self,
1985        event_type: &str,
1986        user_id: &str,
1987        method: &str,
1988        metadata: &CredentialMetadata,
1989    ) {
1990        if !self.config.audit.enabled {
1991            return;
1992        }
1993        let should_log = match event_type {
1994            "auth_success" | "mfa_required" => self.config.audit.log_success,
1995            "auth_failure" => self.config.audit.log_failures,
1996            _ => true,
1997        };
1998        if should_log {
1999            self.audit_manager
2000                .log_auth_trace_event(
2001                    event_type,
2002                    user_id,
2003                    method,
2004                    metadata.client_ip.as_deref().unwrap_or("unknown"),
2005                    metadata.user_agent.as_deref().unwrap_or("unknown"),
2006                )
2007                .await;
2008        }
2009    }
2010
2011    /// Guard the global MFA-challenge budget and store the challenge.
2012    async fn guard_and_store_mfa_challenge(&self, challenge: MfaChallenge) -> Result<()> {
2013        self.mfa_manager.guard_and_store(challenge).await
2014    }
2015
2016    /// Create and immediately store an auth token, returning it.
2017    async fn mint_and_store_token(
2018        &self,
2019        user_id: &str,
2020        scopes: impl Into<crate::types::Scopes>,
2021        method: &str,
2022        lifetime: Option<Duration>,
2023    ) -> Result<AuthToken> {
2024        let token = self
2025            .token_manager
2026            .create_auth_token(user_id, scopes, method, lifetime)?;
2027        self.storage.store_token(&token).await?;
2028        Ok(token)
2029    }
2030
2031    /// Coordinate session state across distributed instances.
2032    pub async fn coordinate_distributed_sessions(&self) -> Result<SessionCoordinationStats> {
2033        self.session_manager.coordinate_distributed_sessions().await
2034    }
2035
2036    /// Synchronize a specific session with remote instances.
2037    pub async fn synchronize_session(&self, session_id: &str) -> Result<()> {
2038        self.session_manager.synchronize_session(session_id).await
2039    }
2040
2041    /// Returns the monitoring manager for metrics collection and health checks.
2042    pub fn monitoring_manager(&self) -> Arc<crate::monitoring::MonitoringManager> {
2043        self.monitoring_manager.clone()
2044    }
2045
2046    /// Returns the security manager for rate limiting, DoS protection, and IP blacklisting.
2047    #[cfg(feature = "api-server")]
2048    pub fn security_manager(&self) -> Option<Arc<crate::api::SecurityManager>> {
2049        Some(self.security_manager.clone())
2050    }
2051
2052    /// Return current performance metrics (token counts, latencies, etc.).
2053    pub async fn get_performance_metrics(&self) -> std::collections::HashMap<String, u64> {
2054        self.monitoring_manager.get_performance_metrics()
2055    }
2056
2057    /// Run a health check on all sub-systems (storage, token engine, etc.).
2058    pub async fn health_check(
2059        &self,
2060    ) -> Result<std::collections::HashMap<String, crate::monitoring::HealthCheckResult>> {
2061        self.monitoring_manager.health_check().await
2062    }
2063
2064    /// Export all collected metrics in Prometheus text exposition format.
2065    pub async fn export_prometheus_metrics(&self) -> String {
2066        self.monitoring_manager.export_prometheus_metrics().await
2067    }
2068    /// Create a new role.
2069    pub async fn create_role(&self, role: crate::permissions::Role) -> Result<()> {
2070        self.require_initialized()?;
2071        self.authorization_manager.create_role(role).await
2072    }
2073
2074    /// Return all defined roles.
2075    pub async fn list_roles(&self) -> Vec<crate::permissions::Role> {
2076        self.authorization_manager.list_roles().await
2077    }
2078
2079    /// Fetch a role definition by name.
2080    pub async fn get_role(&self, role_name: &str) -> Result<crate::permissions::Role> {
2081        self.authorization_manager.get_role(role_name).await
2082    }
2083
2084    /// Add a permission to an existing role.
2085    pub async fn add_role_permission(
2086        &self,
2087        role_name: &str,
2088        permission: crate::permissions::Permission,
2089    ) -> Result<()> {
2090        self.authorization_manager
2091            .add_role_permission(role_name, permission)
2092            .await
2093    }
2094
2095    /// Assign a role to a user.
2096    pub async fn assign_role(&self, user_id: &str, role_name: &str) -> Result<()> {
2097        self.require_initialized()?;
2098        self.authorization_manager
2099            .assign_role(user_id, role_name)
2100            .await
2101    }
2102
2103    /// Remove a role from a user.
2104    pub async fn remove_role(&self, user_id: &str, role_name: &str) -> Result<()> {
2105        self.require_initialized()?;
2106        self.authorization_manager
2107            .remove_role(user_id, role_name)
2108            .await
2109    }
2110
2111    /// Set role inheritance.
2112    pub async fn set_role_inheritance(&self, child_role: &str, parent_role: &str) -> Result<()> {
2113        self.require_initialized()?;
2114        self.authorization_manager
2115            .set_role_inheritance(child_role, parent_role)
2116            .await
2117    }
2118
2119    /// Revoke permission from a user.
2120    pub async fn revoke_permission(
2121        &self,
2122        user_id: &str,
2123        action: &str,
2124        resource: &str,
2125    ) -> Result<()> {
2126        self.require_initialized()?;
2127        self.authorization_manager
2128            .revoke_permission(user_id, action, resource)
2129            .await
2130    }
2131
2132    /// Check if user has a role.
2133    pub async fn user_has_role(&self, user_id: &str, role_name: &str) -> Result<bool> {
2134        self.authorization_manager
2135            .user_has_role(user_id, role_name)
2136            .await
2137    }
2138
2139    /// List the currently assigned runtime roles for a user.
2140    pub async fn list_user_roles(&self, user_id: &str) -> Result<Vec<String>> {
2141        self.authorization_manager.list_user_roles(user_id).await
2142    }
2143
2144    /// Get effective permissions for a user.
2145    pub async fn get_effective_permissions(&self, user_id: &str) -> Result<Vec<String>> {
2146        self.authorization_manager
2147            .get_effective_permissions(user_id)
2148            .await
2149    }
2150
2151    /// Create ABAC policy.
2152    pub async fn create_abac_policy(&self, name: &str, description: &str) -> Result<()> {
2153        self.authorization_manager
2154            .create_abac_policy(name, description)
2155            .await
2156    }
2157
2158    /// Set a user attribute value for ABAC (Attribute-Based Access Control) evaluation.
2159    ///
2160    /// User attributes are key-value pairs associated with users that can be used
2161    /// in dynamic permission rules. This method stores or updates an attribute value.
2162    ///
2163    /// # Parameters
2164    /// - `user_id`: The ID of the user to set the attribute for
2165    /// - `attribute`: The name of the attribute to set
2166    /// - `value`: The value to assign to the attribute
2167    ///
2168    /// # Example
2169    /// ```rust,no_run
2170    /// # use auth_framework::prelude::*;
2171    /// # async fn example(auth: &AuthFramework) -> Result<(), AuthError> {
2172    /// // Set user attributes for policy evaluation
2173    /// auth.map_user_attribute("example_user", "department", "engineering").await?;
2174    /// auth.map_user_attribute("example_user", "clearance_level", "confidential").await?;
2175    /// # Ok(())
2176    /// # }
2177    /// ```
2178    pub async fn map_user_attribute(
2179        &self,
2180        user_id: &str,
2181        attribute: &str,
2182        value: &str,
2183    ) -> Result<()> {
2184        self.authorization_manager
2185            .map_user_attribute(user_id, attribute, value)
2186            .await
2187    }
2188
2189    /// Get a user attribute value for ABAC (Attribute-Based Access Control) evaluation.
2190    ///
2191    /// User attributes are key-value pairs associated with users that can be used
2192    /// in dynamic permission rules. Common attributes include department, clearance level,
2193    /// location, etc.
2194    ///
2195    /// # Parameters
2196    /// - `user_id`: The ID of the user whose attribute to retrieve
2197    /// - `attribute`: The name of the attribute to retrieve
2198    ///
2199    /// # Returns
2200    /// Returns `Some(value)` if the attribute exists, `None` if it doesn't exist.
2201    ///
2202    /// # Example
2203    /// ```rust,no_run
2204    /// # use auth_framework::prelude::*;
2205    /// # async fn example(auth: &AuthFramework) -> Result<(), AuthError> {
2206    /// if let Some(dept) = auth.get_user_attribute("example_user", "department").await? {
2207    ///     println!("User is in department: {}", dept);
2208    /// }
2209    /// # Ok(())
2210    /// # }
2211    /// ```
2212    pub async fn get_user_attribute(
2213        &self,
2214        user_id: &str,
2215        attribute: &str,
2216    ) -> Result<Option<String>> {
2217        self.authorization_manager
2218            .get_user_attribute(user_id, attribute)
2219            .await
2220    }
2221
2222    /// Check dynamic permission with context evaluation (ABAC - Attribute-Based Access Control).
2223    ///
2224    /// This method evaluates permissions based on user attributes, resource attributes,
2225    /// and environmental context rather than just role assignments. It's more flexible
2226    /// than simple role-based checks but requires more complex policy rules.
2227    ///
2228    /// # Parameters
2229    /// - `user_id`: The ID of the user requesting access
2230    /// - `action`: The action being requested (e.g., "read", "write", "delete")
2231    /// - `resource`: The resource being accessed (e.g., "documents", "users", "reports/123")
2232    /// - `context`: Additional context key-value pairs for policy evaluation
2233    ///
2234    /// # Returns
2235    /// Returns `true` if the permission is granted based on the dynamic policy evaluation.
2236    ///
2237    /// # Example
2238    /// ```rust,no_run
2239    /// # use auth_framework::prelude::*;
2240    /// # use std::collections::HashMap;
2241    /// # async fn example(auth: &AuthFramework) -> Result<(), AuthError> {
2242    /// let mut context = HashMap::new();
2243    /// context.insert("time_of_day".to_string(), "business_hours".to_string());
2244    /// context.insert("ip_location".to_string(), "office".to_string());
2245    ///
2246    /// if auth.check_dynamic_permission("example_user", "read", "confidential_docs", context).await? {
2247    ///     println!("Access granted based on dynamic policy");
2248    /// }
2249    /// # Ok(())
2250    /// # }
2251    /// ```
2252    pub async fn check_dynamic_permission(
2253        &self,
2254        user_id: &str,
2255        action: &str,
2256        resource: &str,
2257        context: std::collections::HashMap<String, String>,
2258    ) -> Result<bool> {
2259        self.authorization_manager
2260            .check_dynamic_permission(user_id, action, resource, context)
2261            .await
2262    }
2263
2264    /// Check dynamic permission using a structured context (preferred).
2265    ///
2266    /// Prefer [`check_dynamic_permission_with_context`](Self::check_dynamic_permission_with_context)
2267    /// with a [`PermissionContext`] for better type safety and readability.
2268    ///
2269    /// # Example
2270    /// ```rust,no_run
2271    /// # use auth_framework::{prelude::*, auth_operations::PermissionContext};
2272    /// # async fn example(auth: &AuthFramework) -> Result<(), AuthError> {
2273    /// let context = PermissionContext::new()
2274    ///     .with_attribute("time_of_day", "business_hours")
2275    ///     .with_attribute("ip_location", "office");
2276    ///
2277    /// if auth.check_dynamic_permission_with_context("example_user", "read", "confidential_docs", context).await? {
2278    ///     println!("Access granted based on dynamic policy");
2279    /// }
2280    /// # Ok(())
2281    /// # }
2282    /// ```
2283    pub async fn check_dynamic_permission_with_context(
2284        &self,
2285        user_id: &str,
2286        action: &str,
2287        resource: &str,
2288        context: PermissionContext,
2289    ) -> Result<bool> {
2290        self.check_dynamic_permission(user_id, action, resource, context.into_attributes())
2291            .await
2292    }
2293
2294    /// Create resource for permission management.
2295    pub async fn create_resource(&self, resource: &str) -> Result<()> {
2296        self.authorization_manager.create_resource(resource).await
2297    }
2298
2299    /// Delegate permission from one user to another using a [`DelegationRequest`].
2300    ///
2301    /// This is the preferred method for delegation as it avoids passing multiple
2302    /// parameters and makes the call site self-documenting.
2303    ///
2304    /// # Example
2305    ///
2306    /// ```rust,no_run
2307    /// # use auth_framework::{AuthFramework, AuthConfig};
2308    /// # use auth_framework::auth_operations::DelegationRequest;
2309    /// # use std::time::Duration;
2310    /// # async fn example(auth: &AuthFramework) -> Result<(), auth_framework::errors::AuthError> {
2311    /// let req = DelegationRequest::new("admin_1", "user_2", "write", "reports")
2312    ///     .duration(Duration::from_secs(3600));
2313    /// auth.delegate_permission_with_request(req).await?;
2314    /// # Ok(())
2315    /// # }
2316    /// ```
2317    pub async fn delegate_permission_with_request(&self, req: DelegationRequest) -> Result<()> {
2318        self.authorization_manager
2319            .delegate_permission(
2320                req.delegator_id(),
2321                req.delegatee_id(),
2322                req.action(),
2323                req.resource(),
2324                req.get_duration(),
2325            )
2326            .await
2327    }
2328
2329    /// Delegate permission from one user to another.
2330    ///
2331    /// Prefer [`delegate_permission_with_request`](Self::delegate_permission_with_request)
2332    /// with a [`DelegationRequest`] for better readability when delegating permissions.
2333    pub async fn delegate_permission(
2334        &self,
2335        delegator_id: &str,
2336        delegatee_id: &str,
2337        action: &str,
2338        resource: &str,
2339        duration: std::time::Duration,
2340    ) -> Result<()> {
2341        self.authorization_manager
2342            .delegate_permission(delegator_id, delegatee_id, action, resource, duration)
2343            .await
2344    }
2345
2346    /// Get active delegations for a user.
2347    pub async fn get_active_delegations(&self, user_id: &str) -> Result<Vec<String>> {
2348        self.authorization_manager
2349            .get_active_delegations(user_id)
2350            .await
2351    }
2352
2353    /// Get permission audit logs with filtering.
2354    pub async fn get_permission_audit_logs(
2355        &self,
2356        user_id: Option<&str>,
2357        action: Option<&str>,
2358        resource: Option<&str>,
2359        limit: Option<usize>,
2360    ) -> Result<Vec<String>> {
2361        self.audit_manager
2362            .get_permission_audit_logs(user_id, action, resource, limit)
2363            .await
2364    }
2365
2366    /// Get permission audit logs using an [`AuditLogQuery`] for better readability.
2367    ///
2368    /// Prefer [`get_permission_audit_logs_with_query`](Self::get_permission_audit_logs_with_query)
2369    /// with an [`AuditLogQuery`] for better readability when using multiple filters.
2370    ///
2371    /// # Example
2372    ///
2373    /// ```rust,no_run
2374    /// # use auth_framework::{prelude::*, auth_operations::AuditLogQuery};
2375    /// # async fn example(auth: &AuthFramework) -> Result<(), auth_framework::errors::AuthError> {
2376    /// let logs = auth.get_permission_audit_logs_with_query(
2377    ///     AuditLogQuery::new()
2378    ///         .user("user_123")
2379    ///         .action("read")
2380    ///         .limit(50)
2381    /// ).await?;
2382    /// # Ok(())
2383    /// # }
2384    /// ```
2385    pub async fn get_permission_audit_logs_with_query(
2386        &self,
2387        query: AuditLogQuery,
2388    ) -> Result<Vec<String>> {
2389        self.audit_manager
2390            .get_permission_audit_logs(
2391                query.get_user_id(),
2392                query.get_action(),
2393                query.get_resource(),
2394                query.get_limit(),
2395            )
2396            .await
2397    }
2398
2399    /// Get permission metrics for monitoring.
2400    pub async fn get_permission_metrics(
2401        &self,
2402    ) -> Result<std::collections::HashMap<String, u64>, AuthError> {
2403        let active_sessions = self.storage.count_active_sessions().await.unwrap_or(0);
2404        let permission_checks_last_hour = self
2405            .audit_manager
2406            .get_permission_checks_last_hour()
2407            .await
2408            .unwrap_or(0);
2409        self.authorization_manager
2410            .get_permission_metrics(active_sessions, permission_checks_last_hour)
2411            .await
2412    }
2413
2414    /// Collect comprehensive security audit statistics.
2415    pub async fn get_security_audit_stats(&self) -> Result<SecurityAuditStats> {
2416        let active_sessions = self
2417            .session_manager
2418            .count_active_sessions()
2419            .await
2420            .unwrap_or(0);
2421        self.audit_manager
2422            .get_security_audit_stats(active_sessions)
2423            .await
2424    }
2425
2426    /// Get user profile information
2427    pub async fn get_user_profile(
2428        &self,
2429        user_id: &str,
2430    ) -> Result<crate::providers::ProviderProfile> {
2431        self.user_manager.get_user_profile(user_id).await
2432    }
2433}
2434
2435pub use crate::audit::SecurityAuditStats;
2436
2437pub use crate::auth_modular::session_manager::SessionCoordinationStats;
2438
2439/// Authentication framework statistics.
2440#[derive(Debug, Clone, Default)]
2441pub struct AuthStats {
2442    /// Number of registered authentication methods
2443    pub registered_methods: Vec<String>,
2444
2445    /// Number of active sessions
2446    pub active_sessions: u64,
2447
2448    /// Number of active MFA challenges
2449    pub active_mfa_challenges: u64,
2450
2451    /// Number of tokens issued (this would need proper tracking)
2452    pub tokens_issued: u64,
2453
2454    /// Number of authentication attempts (this would need proper tracking)
2455    pub auth_attempts: u64,
2456}
2457
2458#[cfg(test)]
2459mod tests {
2460    use super::*;
2461    use crate::config::{AuthConfig, SecurityConfig};
2462    #[tokio::test]
2463    async fn test_framework_initialization() {
2464        let config = AuthConfig::new().security(SecurityConfig {
2465            min_password_length: 8,
2466            require_password_complexity: false,
2467            password_hash_algorithm: crate::config::PasswordHashAlgorithm::Bcrypt,
2468            jwt_algorithm: crate::config::JwtAlgorithm::HS256,
2469            secret_key: Some("test_secret_key_32_bytes_long!!!!".to_string()),
2470            secure_cookies: false,
2471            cookie_same_site: crate::config::CookieSameSite::Lax,
2472            csrf_protection: false,
2473            session_timeout: Duration::from_secs(3600),
2474            previous_secret_key: None,
2475        });
2476        let mut framework = AuthFramework::new(config);
2477
2478        assert!(framework.initialize().await.is_ok());
2479        assert!(framework.initialized);
2480    }
2481
2482    #[tokio::test]
2483    async fn test_method_registration() {
2484        // Method registration test disabled due to trait object lifetime constraints
2485        // This test would require dynamic trait objects which have complex lifetime requirements
2486        // Production implementations should use static method registration or dependency injection
2487
2488        let config = AuthConfig::new().security(SecurityConfig {
2489            min_password_length: 8,
2490            require_password_complexity: false,
2491            password_hash_algorithm: crate::config::PasswordHashAlgorithm::Bcrypt,
2492            jwt_algorithm: crate::config::JwtAlgorithm::HS256,
2493            secret_key: Some("test_secret_key_32_bytes_long!!!!".to_string()),
2494            secure_cookies: false,
2495            cookie_same_site: crate::config::CookieSameSite::Lax,
2496            csrf_protection: false,
2497            session_timeout: Duration::from_secs(3600),
2498            previous_secret_key: None,
2499        });
2500        let framework = AuthFramework::new(config);
2501
2502        // Verify framework initialization works without dynamic method registration
2503        assert!(!framework.initialized);
2504
2505        // Method registration system supports flexible authentication methods
2506        // using factory pattern for better lifetime management
2507    }
2508
2509    #[tokio::test]
2510    async fn test_token_validation() {
2511        let config = AuthConfig::new().security(SecurityConfig {
2512            min_password_length: 8,
2513            require_password_complexity: false,
2514            password_hash_algorithm: crate::config::PasswordHashAlgorithm::Bcrypt,
2515            jwt_algorithm: crate::config::JwtAlgorithm::HS256,
2516            secret_key: Some("test_secret_key_32_bytes_long!!!!".to_string()),
2517            secure_cookies: false,
2518            cookie_same_site: crate::config::CookieSameSite::Lax,
2519            csrf_protection: false,
2520            session_timeout: Duration::from_secs(3600),
2521            previous_secret_key: None,
2522        });
2523        let mut framework = AuthFramework::new(config);
2524        framework.initialize().await.unwrap();
2525
2526        let token = framework
2527            .token_manager
2528            .create_auth_token("test-user", vec!["read".to_string()], "test", None)
2529            .unwrap();
2530
2531        // Store the token first
2532        framework.storage.store_token(&token).await.unwrap();
2533
2534        assert!(framework.validate_token(&token).await.unwrap());
2535    }
2536
2537    #[tokio::test]
2538    async fn test_session_management() {
2539        let config = AuthConfig::new().security(SecurityConfig {
2540            min_password_length: 8,
2541            require_password_complexity: false,
2542            password_hash_algorithm: crate::config::PasswordHashAlgorithm::Bcrypt,
2543            jwt_algorithm: crate::config::JwtAlgorithm::HS256,
2544            secret_key: Some("test_secret_key_32_bytes_long!!!!".to_string()),
2545            secure_cookies: false,
2546            cookie_same_site: crate::config::CookieSameSite::Lax,
2547            csrf_protection: false,
2548            session_timeout: Duration::from_secs(3600),
2549            previous_secret_key: None,
2550        });
2551        let mut framework = AuthFramework::new(config);
2552        framework.initialize().await.unwrap();
2553
2554        let session_id = framework
2555            .create_session(
2556                "test-user",
2557                Duration::from_secs(3600),
2558                Some("192.168.1.1".to_string()),
2559                Some("Test Agent".to_string()),
2560            )
2561            .await
2562            .unwrap();
2563
2564        let session = framework.get_session(&session_id).await.unwrap();
2565        assert!(session.is_some());
2566
2567        framework.delete_session(&session_id).await.unwrap();
2568        let session = framework.get_session(&session_id).await.unwrap();
2569        assert!(session.is_none());
2570    }
2571
2572    #[tokio::test]
2573    async fn test_grouped_operations_accessors() {
2574        let config = AuthConfig::new().security(SecurityConfig {
2575            min_password_length: 8,
2576            require_password_complexity: false,
2577            password_hash_algorithm: crate::config::PasswordHashAlgorithm::Bcrypt,
2578            jwt_algorithm: crate::config::JwtAlgorithm::HS256,
2579            secret_key: Some("test_secret_key_32_bytes_long!!!!".to_string()),
2580            secure_cookies: false,
2581            cookie_same_site: crate::config::CookieSameSite::Lax,
2582            csrf_protection: false,
2583            session_timeout: Duration::from_secs(3600),
2584            previous_secret_key: None,
2585        });
2586        let mut framework = AuthFramework::new(config);
2587        framework.initialize().await.unwrap();
2588
2589        let user_id = framework
2590            .users()
2591            .register("grouped-user", "grouped-user@example.com", "P@ssw0rd123")
2592            .await
2593            .unwrap();
2594        assert!(
2595            framework
2596                .users()
2597                .exists_by_username("grouped-user")
2598                .await
2599                .unwrap()
2600        );
2601
2602        let session_id = framework
2603            .sessions()
2604            .create(&user_id, Duration::from_secs(300), None, None)
2605            .await
2606            .unwrap();
2607        assert!(
2608            framework
2609                .sessions()
2610                .get(&session_id)
2611                .await
2612                .unwrap()
2613                .is_some()
2614        );
2615        assert_eq!(
2616            framework
2617                .sessions()
2618                .list_for_user(&user_id)
2619                .await
2620                .unwrap()
2621                .len(),
2622            1
2623        );
2624
2625        framework
2626            .authorization()
2627            .grant(&user_id, "read", "documents")
2628            .await
2629            .unwrap();
2630        let permissions = framework
2631            .authorization()
2632            .effective_permissions(&user_id)
2633            .await
2634            .unwrap();
2635        assert!(
2636            permissions
2637                .iter()
2638                .any(|permission| permission == "read:documents")
2639        );
2640
2641        framework.sessions().delete(&session_id).await.unwrap();
2642        assert!(
2643            framework
2644                .sessions()
2645                .get(&session_id)
2646                .await
2647                .unwrap()
2648                .is_none()
2649        );
2650    }
2651
2652    #[tokio::test]
2653    async fn test_cleanup_expired_data() {
2654        let config = AuthConfig::new().security(SecurityConfig {
2655            min_password_length: 8,
2656            require_password_complexity: false,
2657            password_hash_algorithm: crate::config::PasswordHashAlgorithm::Bcrypt,
2658            jwt_algorithm: crate::config::JwtAlgorithm::HS256,
2659            secret_key: Some("test_secret_key_32_bytes_long!!!!".to_string()),
2660            secure_cookies: false,
2661            cookie_same_site: crate::config::CookieSameSite::Lax,
2662            csrf_protection: false,
2663            session_timeout: Duration::from_secs(3600),
2664            previous_secret_key: None,
2665        });
2666        let mut framework = AuthFramework::new(config);
2667        framework.initialize().await.unwrap();
2668
2669        // This test would need expired data to be meaningful
2670        assert!(framework.cleanup_expired_data().await.is_ok());
2671    }
2672}