Skip to main content

auth_framework/
auth_operations.rs

1//! Grouped operation facades over [`AuthFramework`].
2//!
3//! Each `*Operations` struct is a lightweight view (holds only a lifetime-bound
4//! reference to the framework) that exposes a focused subset of the full API.
5//! They are created by the corresponding accessor on `AuthFramework` (e.g. [`users()`]).
6//!
7//! # Request structs
8//!
9//! Several operations accept structured request types instead of long
10//! parameter lists.  These types carry required parameters via a
11//! constructor and optional parameters via builder methods:
12//!
13//! - [`SessionCreateRequest`] — session creation with optional IP / user-agent.
14//! - [`AuditLogQuery`] — filtered audit log queries.
15//! - [`UserListQuery`] — user listing with pagination and filtering.
16//! - [`PermissionContext`] — context data for dynamic permission evaluation.
17//! - [`DelegationRequest`] — permission delegation with required fields.
18//! - [`ExecutionMode`] — `DryRun` vs `Execute` for maintenance operations.
19//! - [`UserStatus`] — `Active` vs `Inactive` for user account state.
20//! - [`SessionFilter`] — `ActiveOnly` vs `IncludeInactive` for session listing.
21//!
22//! [`users()`]: crate::auth::AuthFramework::users
23
24use crate::audit::SecurityAuditStats;
25use crate::auth::{AuthFramework, AuthStats, UserInfo};
26use crate::errors::{AuthError, Result};
27use crate::maintenance::{BackupReport, ResetReport, RestoreReport};
28use crate::methods::MfaChallenge;
29use crate::permissions::Role;
30use crate::storage::SessionData;
31use crate::tokens::AuthToken;
32use std::sync::Arc;
33use std::time::Duration;
34
35/// Controls whether a maintenance operation (backup, restore, reset) actually
36/// modifies state or merely previews what *would* happen.
37///
38/// Replaces bare `bool` parameters for better call-site readability.
39///
40/// # Example
41///
42/// ```rust,ignore
43/// use auth_framework::auth_operations::ExecutionMode;
44///
45/// // Preview:
46/// let preview = auth.maintenance().backup("backup.json", ExecutionMode::DryRun).await?;
47/// // For real:
48/// let report = auth.maintenance().backup("backup.json", ExecutionMode::Execute).await?;
49/// ```
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
51pub enum ExecutionMode {
52    /// Report what the operation would do without making changes.
53    DryRun,
54    /// Actually perform the operation.
55    Execute,
56}
57
58impl ExecutionMode {
59    /// Returns `true` when this is a dry-run (preview) execution.
60    pub fn is_dry_run(self) -> bool {
61        matches!(self, Self::DryRun)
62    }
63}
64
65impl From<ExecutionMode> for bool {
66    /// Converts to the legacy `dry_run: bool` parameter (`DryRun → true`).
67    fn from(mode: ExecutionMode) -> bool {
68        mode.is_dry_run()
69    }
70}
71
72/// Whether a user account should be active (able to log in) or inactive
73/// (locked out).
74///
75/// Replaces bare `bool` parameters for better call-site readability.
76///
77/// # Example
78///
79/// ```rust,ignore
80/// use auth_framework::auth_operations::UserStatus;
81///
82/// // Deactivate a user:
83/// auth.users().set_status(&user_id, UserStatus::Inactive).await?;
84/// // Re-activate:
85/// auth.users().set_status(&user_id, UserStatus::Active).await?;
86/// ```
87#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
88pub enum UserStatus {
89    /// Account is active and can authenticate.
90    Active,
91    /// Account is disabled and all login attempts will be rejected.
92    Inactive,
93}
94
95impl UserStatus {
96    /// Returns `true` when the user should be active.
97    pub fn is_active(self) -> bool {
98        matches!(self, Self::Active)
99    }
100}
101
102impl From<UserStatus> for bool {
103    /// Converts to the legacy `active: bool` parameter (`Active → true`).
104    fn from(status: UserStatus) -> bool {
105        status.is_active()
106    }
107}
108
109impl From<bool> for UserStatus {
110    fn from(active: bool) -> Self {
111        if active { Self::Active } else { Self::Inactive }
112    }
113}
114
115/// Filter for session listing queries.
116///
117/// Replaces `include_inactive: bool` for self-documenting call sites.
118///
119/// # Example
120///
121/// ```rust,ignore
122/// use auth_framework::auth_operations::SessionFilter;
123///
124/// let active = mgr.get_user_sessions(user_id, SessionFilter::ActiveOnly).await?;
125/// let all    = mgr.get_user_sessions(user_id, SessionFilter::IncludeInactive).await?;
126/// ```
127#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
128pub enum SessionFilter {
129    /// Return only active sessions.
130    ActiveOnly,
131    /// Return all sessions including expired/revoked ones.
132    IncludeInactive,
133}
134
135impl SessionFilter {
136    /// Returns `true` when inactive sessions should be included.
137    pub fn include_inactive(self) -> bool {
138        matches!(self, Self::IncludeInactive)
139    }
140}
141
142impl From<SessionFilter> for bool {
143    /// Converts to the legacy `include_inactive: bool` parameter.
144    fn from(filter: SessionFilter) -> bool {
145        filter.include_inactive()
146    }
147}
148
149// ──────────────────────────────────────────────────────────────────────────────
150// Request / query structs
151// ──────────────────────────────────────────────────────────────────────────────
152
153/// Filtering criteria for [`AuditOperations::query_permission_logs`].
154///
155/// All fields are optional — an empty query returns unfiltered results.
156///
157/// # Example
158///
159/// ```rust,ignore
160/// let query = AuditLogQuery::new()
161///     .user("user_123")
162///     .action("read")
163///     .limit(50);
164/// ```
165#[derive(Debug, Clone, Default)]
166pub struct AuditLogQuery {
167    user_id: Option<String>,
168    action: Option<String>,
169    resource: Option<String>,
170    limit: Option<usize>,
171}
172
173impl AuditLogQuery {
174    /// Create an empty query (matches everything).
175    pub fn new() -> Self {
176        Self::default()
177    }
178
179    /// Filter by user ID.
180    pub fn user(mut self, user_id: impl Into<String>) -> Self {
181        self.user_id = Some(user_id.into());
182        self
183    }
184
185    /// Filter by action (e.g. `"read"`, `"write"`).
186    pub fn action(mut self, action: impl Into<String>) -> Self {
187        self.action = Some(action.into());
188        self
189    }
190
191    /// Filter by resource path.
192    pub fn resource(mut self, resource: impl Into<String>) -> Self {
193        self.resource = Some(resource.into());
194        self
195    }
196
197    /// Limit the number of returned entries.
198    pub fn limit(mut self, limit: usize) -> Self {
199        self.limit = Some(limit);
200        self
201    }
202
203    /// Returns the user-ID filter, if set.
204    pub fn get_user_id(&self) -> Option<&str> {
205        self.user_id.as_deref()
206    }
207
208    /// Returns the action filter, if set.
209    pub fn get_action(&self) -> Option<&str> {
210        self.action.as_deref()
211    }
212
213    /// Returns the resource filter, if set.
214    pub fn get_resource(&self) -> Option<&str> {
215        self.resource.as_deref()
216    }
217
218    /// Returns the maximum number of entries to return, if set.
219    pub fn get_limit(&self) -> Option<usize> {
220        self.limit
221    }
222}
223
224/// Query type for listing users with pagination and filtering.
225///
226/// Provides a fluent API for configuring user listing parameters.
227///
228/// # Example
229///
230/// ```rust
231/// # use auth_framework::auth_operations::UserListQuery;
232/// let query = UserListQuery::new()
233///     .limit(50)
234///     .active_only();
235/// ```
236#[derive(Debug, Clone, Default)]
237pub struct UserListQuery {
238    limit: Option<usize>,
239    offset: Option<usize>,
240    active_only: bool,
241}
242
243impl UserListQuery {
244    /// Create an empty query (returns all users).
245    pub fn new() -> Self {
246        Self::default()
247    }
248
249    /// Limit the number of users returned.
250    pub fn limit(mut self, limit: usize) -> Self {
251        self.limit = Some(limit);
252        self
253    }
254
255    /// Skip the first N users (for pagination).
256    pub fn offset(mut self, offset: usize) -> Self {
257        self.offset = Some(offset);
258        self
259    }
260
261    /// Only return active users (default: false).
262    pub fn active_only(mut self) -> Self {
263        self.active_only = true;
264        self
265    }
266
267    /// Conditionally restrict the query to active users.
268    pub fn active_only_if(mut self, active_only: bool) -> Self {
269        self.active_only = active_only;
270        self
271    }
272
273    /// Conditionally apply a limit when one is provided.
274    pub fn limit_if_some(mut self, limit: Option<usize>) -> Self {
275        if let Some(limit) = limit {
276            self.limit = Some(limit);
277        }
278        self
279    }
280
281    /// Returns the maximum number of users to return, if set.
282    pub fn get_limit(&self) -> Option<usize> {
283        self.limit
284    }
285
286    /// Returns the pagination offset, if set.
287    pub fn get_offset(&self) -> Option<usize> {
288        self.offset
289    }
290
291    /// Returns `true` when only active users should be listed.
292    pub fn get_active_only(&self) -> bool {
293        self.active_only
294    }
295}
296
297/// Context data for dynamic permission evaluation (ABAC).
298///
299/// Provides a structured way to pass environmental and contextual information
300/// for attribute-based access control decisions.
301///
302/// # Example
303///
304/// ```rust
305/// # use auth_framework::auth_operations::PermissionContext;
306/// let context = PermissionContext::new()
307///     .with_attribute("time_of_day", "business_hours")
308///     .with_attribute("ip_location", "office")
309///     .with_attribute("device_type", "trusted");
310/// ```
311#[derive(Debug, Clone, Default)]
312pub struct PermissionContext {
313    attributes: std::collections::HashMap<String, String>,
314}
315
316impl PermissionContext {
317    /// Create an empty context.
318    pub fn new() -> Self {
319        Self::default()
320    }
321
322    /// Add a context attribute.
323    pub fn with_attribute(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
324        self.attributes.insert(key.into(), value.into());
325        self
326    }
327
328    /// Add multiple attributes from an iterator.
329    pub fn with_attributes<I, K, V>(mut self, attributes: I) -> Self
330    where
331        I: IntoIterator<Item = (K, V)>,
332        K: Into<String>,
333        V: Into<String>,
334    {
335        for (key, value) in attributes {
336            self.attributes.insert(key.into(), value.into());
337        }
338        self
339    }
340
341    /// Get the underlying attributes map.
342    pub fn into_attributes(self) -> std::collections::HashMap<String, String> {
343        self.attributes
344    }
345
346    /// Get a reference to the attributes map.
347    pub fn attributes(&self) -> &std::collections::HashMap<String, String> {
348        &self.attributes
349    }
350}
351
352/// Request type for [`AdminOperations::delegate`].
353///
354/// Bundles the four required delegation fields and the optional duration
355/// into a single self-documenting value.
356///
357/// # Example
358///
359/// ```rust,ignore
360/// let req = DelegationRequest::new("admin_1", "user_2", "write", "reports")
361///     .duration(Duration::from_secs(3600));
362/// ```
363#[derive(Debug, Clone)]
364pub struct DelegationRequest {
365    delegator_id: String,
366    delegatee_id: String,
367    action: String,
368    resource: String,
369    duration: Duration,
370}
371
372impl DelegationRequest {
373    /// Create a delegation request with required parameters.
374    ///
375    /// The default duration is 1 hour. Override with [`duration`](Self::duration).
376    pub fn new(
377        delegator_id: impl Into<String>,
378        delegatee_id: impl Into<String>,
379        action: impl Into<String>,
380        resource: impl Into<String>,
381    ) -> Self {
382        Self {
383            delegator_id: delegator_id.into(),
384            delegatee_id: delegatee_id.into(),
385            action: action.into(),
386            resource: resource.into(),
387            duration: Duration::from_secs(3600),
388        }
389    }
390
391    /// Set the delegation duration (replaces the default of 1 hour).
392    pub fn duration(mut self, duration: Duration) -> Self {
393        self.duration = duration;
394        self
395    }
396
397    /// Returns the ID of the user granting permissions.
398    pub fn delegator_id(&self) -> &str {
399        &self.delegator_id
400    }
401
402    /// Returns the ID of the user receiving permissions.
403    pub fn delegatee_id(&self) -> &str {
404        &self.delegatee_id
405    }
406
407    /// Returns the action being delegated (e.g. `"write"`).
408    pub fn action(&self) -> &str {
409        &self.action
410    }
411
412    /// Returns the resource being delegated (e.g. `"reports"`).
413    pub fn resource(&self) -> &str {
414        &self.resource
415    }
416
417    /// Returns how long the delegation is valid.
418    pub fn get_duration(&self) -> Duration {
419        self.duration
420    }
421}
422
423// ──────────────────────────────────────────────────────────────────────────────
424// User operations
425// ──────────────────────────────────────────────────────────────────────────────
426
427/// Focused user-management operations exposed from [`AuthFramework::users`].
428///
429/// # Example
430///
431/// ```rust,no_run
432/// # use auth_framework::prelude::*;
433/// # async fn example(auth: &AuthFramework) -> Result<(), AuthError> {
434/// // Register
435/// let uid = auth.users().register("alice", "alice@example.com", "P@ssw0rd!").await?;
436///
437/// // Look up
438/// let user = auth.users().get(&uid).await?;
439/// assert_eq!(user.username, "alice");
440///
441/// // Update password
442/// auth.users().update_password_by_id(&uid, "NewP@ss!").await?;
443/// # Ok(())
444/// # }
445/// ```
446pub struct UserOperations<'a> {
447    pub(crate) framework: &'a AuthFramework,
448}
449
450impl UserOperations<'_> {
451    /// Register a new user and return the generated user ID.
452    pub async fn register(&self, username: &str, email: &str, password: &str) -> Result<String> {
453        self.framework
454            .register_user(username, email, password)
455            .await
456    }
457
458    /// List users from the canonical user index.
459    ///
460    /// **Prefer [`list_with_query`](Self::list_with_query)** which uses a
461    /// [`UserListQuery`] builder for better readability at call sites.
462    #[deprecated(
463        since = "0.6.0",
464        note = "use `list_with_query(UserListQuery::new().limit(n).active_only())` instead"
465    )]
466    pub async fn list(
467        &self,
468        limit: Option<usize>,
469        offset: Option<usize>,
470        active_only: bool,
471    ) -> Result<Vec<UserInfo>> {
472        self.framework
473            .list_users_with_query(
474                UserListQuery::new()
475                    .offset(offset.unwrap_or(0))
476                    .active_only_if(active_only)
477                    .limit_if_some(limit),
478            )
479            .await
480    }
481
482    /// List users using a [`UserListQuery`] for better readability.
483    ///
484    /// # Example
485    ///
486    /// ```rust,no_run
487    /// # use auth_framework::prelude::*;
488    /// # async fn example(auth: &AuthFramework) -> Result<(), AuthError> {
489    /// let active = auth.users()
490    ///     .list_with_query(UserListQuery::new().limit(50).active_only())
491    ///     .await?;
492    /// # Ok(())
493    /// # }
494    /// ```
495    pub async fn list_with_query(&self, query: UserListQuery) -> Result<Vec<UserInfo>> {
496        self.framework
497            .list_users_with_query(query)
498            .await
499    }
500
501    /// Fetch a user record by canonical user ID.
502    pub async fn get(&self, user_id: &str) -> Result<UserInfo> {
503        self.framework.get_user_record(user_id).await
504    }
505
506    /// Check whether a username exists.
507    pub async fn exists_by_username(&self, username: &str) -> Result<bool> {
508        self.framework.username_exists(username).await
509    }
510
511    /// Check whether an email exists.
512    pub async fn exists_by_email(&self, email: &str) -> Result<bool> {
513        self.framework.email_exists(email).await
514    }
515
516    /// Fetch a user record by username.
517    pub async fn get_by_username(
518        &self,
519        username: &str,
520    ) -> Result<std::collections::HashMap<String, serde_json::Value>> {
521        self.framework.get_user_by_username(username).await
522    }
523
524    /// Fetch an application-level user profile.
525    pub async fn profile(&self, user_id: &str) -> Result<crate::providers::ProviderProfile> {
526        self.framework.get_user_profile(user_id).await
527    }
528
529    /// Update a user's password.
530    pub async fn update_password(&self, username: &str, new_password: &str) -> Result<()> {
531        self.framework
532            .update_user_password(username, new_password)
533            .await
534    }
535
536    /// Update a user's password by user ID.
537    pub async fn update_password_by_id(&self, user_id: &str, new_password: &str) -> Result<()> {
538        self.framework
539            .update_user_password_by_id(user_id, new_password)
540            .await
541    }
542
543    /// Update the roles assigned to a user.
544    pub async fn update_roles(&self, user_id: &str, roles: &[String]) -> Result<()> {
545        self.framework.update_user_roles(user_id, roles).await
546    }
547
548    /// Enable or disable a user.
549    #[deprecated(since = "0.5.0", note = "use `set_status(id, UserStatus)` instead")]
550    pub async fn set_active(&self, user_id: &str, active: bool) -> Result<()> {
551        self.framework.set_user_active(user_id, active).await
552    }
553
554    /// Change whether a user account is active or inactive.
555    ///
556    /// Inactive users cannot authenticate until re-activated.
557    ///
558    /// # Example
559    ///
560    /// ```rust,ignore
561    /// auth.users().set_status(&user_id, UserStatus::Inactive).await?;
562    /// ```
563    pub async fn set_status(&self, user_id: &str, status: UserStatus) -> Result<()> {
564        self.framework
565            .set_user_active(user_id, status.is_active())
566            .await
567    }
568
569    /// Update a user's email address.
570    pub async fn update_email(&self, user_id: &str, email: &str) -> Result<()> {
571        self.framework.update_user_email(user_id, email).await
572    }
573
574    /// Verify a user's password.
575    pub async fn verify_password(&self, user_id: &str, password: &str) -> Result<bool> {
576        self.framework.verify_user_password(user_id, password).await
577    }
578
579    /// Resolve a username from a user ID.
580    pub async fn username(&self, user_id: &str) -> Result<String> {
581        self.framework.get_username_by_id(user_id).await
582    }
583
584    /// Delete a user by username.
585    pub async fn delete(&self, username: &str) -> Result<()> {
586        self.framework.delete_user(username).await
587    }
588
589    /// Delete a user by user ID.
590    pub async fn delete_by_id(&self, user_id: &str) -> Result<()> {
591        self.framework.delete_user_by_id(user_id).await
592    }
593
594    /// Validate a username against the configured format rules.
595    ///
596    /// Returns `Ok(())` when the username is acceptable, or
597    /// `Err(AuthError::Validation { .. })` describing the policy violation.
598    ///
599    /// # Example
600    ///
601    /// ```rust,no_run
602    /// # use auth_framework::prelude::*;
603    /// # async fn example(auth: &AuthFramework) -> Result<(), AuthError> {
604    /// auth.users().check_username("alice")?;
605    /// // Returns Err explaining why the name is invalid:
606    /// assert!(auth.users().check_username("").is_err());
607    /// # Ok(())
608    /// # }
609    /// ```
610    pub fn check_username(&self, username: &str) -> Result<()> {
611        crate::utils::validation::validate_username(username)
612    }
613
614    /// Validate a password against the active security policy.
615    ///
616    /// Returns `Ok(())` when the password meets production strength
617    /// requirements, or `Err(AuthError::Validation { .. })` with feedback.
618    ///
619    /// # Example
620    ///
621    /// ```rust,no_run
622    /// # use auth_framework::prelude::*;
623    /// # async fn example(auth: &AuthFramework) -> Result<(), AuthError> {
624    /// auth.users().check_password_strength("C0mpl3x!Pa$$word")?;
625    /// assert!(auth.users().check_password_strength("weak").is_err());
626    /// # Ok(())
627    /// # }
628    /// ```
629    pub fn check_password_strength(&self, password: &str) -> Result<()> {
630        let strength = crate::utils::password::check_password_strength(password);
631        if crate::utils::password::meets_production_strength(strength.level) {
632            Ok(())
633        } else {
634            Err(AuthError::validation(format!(
635                "Password does not meet strength requirements: {}",
636                strength.feedback.join(", ")
637            )))
638        }
639    }
640
641    /// Validate an email address against RFC 5322 format rules.
642    ///
643    /// Returns `Ok(())` when the email is acceptable, or
644    /// `Err(AuthError::Validation { .. })` describing the issue.
645    ///
646    /// # Example
647    ///
648    /// ```rust,no_run
649    /// # use auth_framework::prelude::*;
650    /// # async fn example(auth: &AuthFramework) -> Result<(), AuthError> {
651    /// auth.users().check_email("alice@example.com")?;
652    /// assert!(auth.users().check_email("not-an-email").is_err());
653    /// # Ok(())
654    /// # }
655    /// ```
656    pub fn check_email(&self, email: &str) -> Result<()> {
657        crate::utils::validation::validate_email(email)
658    }
659}
660
661// ──────────────────────────────────────────────────────────────────────────────
662// Session operations
663// ──────────────────────────────────────────────────────────────────────────────
664
665/// Request type for [`SessionOperations::create`].
666///
667/// Bundles the required session parameters (user ID, lifetime) with optional
668/// context (IP address, user-agent) so callers never need to pass `None`
669/// explicitly.
670///
671/// # Example
672///
673/// ```rust,no_run
674/// # use auth_framework::auth_operations::SessionCreateRequest;
675/// # use std::time::Duration;
676/// // Minimal — no optional fields:
677/// let req = SessionCreateRequest::new("user-123", Duration::from_secs(3600));
678///
679/// // With optional context:
680/// let req = SessionCreateRequest::new("user-123", Duration::from_secs(3600))
681///     .ip_address("10.0.0.1")
682///     .user_agent("Mozilla/5.0");
683/// ```
684#[derive(Debug, Clone)]
685pub struct SessionCreateRequest {
686    user_id: String,
687    expires_in: Duration,
688    ip_address: Option<String>,
689    user_agent: Option<String>,
690}
691
692impl SessionCreateRequest {
693    /// Create a request with the required fields.
694    pub fn new(user_id: impl Into<String>, expires_in: Duration) -> Self {
695        Self {
696            user_id: user_id.into(),
697            expires_in,
698            ip_address: None,
699            user_agent: None,
700        }
701    }
702
703    /// Attach a client IP address for audit / geolocation.
704    pub fn ip_address(mut self, ip: impl Into<String>) -> Self {
705        self.ip_address = Some(ip.into());
706        self
707    }
708
709    /// Attach a `User-Agent` string for device tracking.
710    pub fn user_agent(mut self, ua: impl Into<String>) -> Self {
711        self.user_agent = Some(ua.into());
712        self
713    }
714
715    /// Returns the user ID this session is being created for.
716    pub fn get_user_id(&self) -> &str {
717        &self.user_id
718    }
719
720    /// Returns how long until the session expires.
721    pub fn get_expires_in(&self) -> Duration {
722        self.expires_in
723    }
724
725    /// Returns the client IP address, if attached.
726    pub fn get_ip_address(&self) -> Option<&str> {
727        self.ip_address.as_deref()
728    }
729
730    /// Returns the `User-Agent` header value, if attached.
731    pub fn get_user_agent(&self) -> Option<&str> {
732        self.user_agent.as_deref()
733    }
734}
735
736/// Focused session-management operations exposed from [`AuthFramework::sessions`].
737///
738/// # Example
739///
740/// ```rust,no_run
741/// # use auth_framework::prelude::*;
742/// # use auth_framework::auth_operations::SessionCreateRequest;
743/// # use std::time::Duration;
744/// # async fn example(auth: &AuthFramework) -> Result<(), AuthError> {
745/// // Using the request struct (recommended):
746/// let req = SessionCreateRequest::new("user-123", Duration::from_secs(3600))
747///     .ip_address("10.0.0.1");
748/// let sid = auth.sessions().create_session(req).await?;
749///
750/// // Positional shorthand still works:
751/// let sid = auth.sessions().create("user-123", Duration::from_secs(3600), None, None).await?;
752///
753/// let session = auth.sessions().get(&sid).await?;
754/// auth.sessions().delete(&sid).await?;
755/// # Ok(())
756/// # }
757/// ```
758pub struct SessionOperations<'a> {
759    pub(crate) framework: &'a AuthFramework,
760}
761
762impl SessionOperations<'_> {
763    /// Create a new session from a [`SessionCreateRequest`].
764    ///
765    /// This is the preferred entry point — it avoids passing `None` for
766    /// optional parameters and makes the call site self-documenting.
767    pub async fn create_session(&self, req: SessionCreateRequest) -> Result<String> {
768        self.framework
769            .create_session(&req.user_id, req.expires_in, req.ip_address, req.user_agent)
770            .await
771    }
772
773    /// Create a new session for a user (positional convenience).
774    ///
775    /// Prefer [`create_session`](Self::create_session) with a
776    /// [`SessionCreateRequest`] when you need optional fields.
777    pub async fn create(
778        &self,
779        user_id: &str,
780        expires_in: Duration,
781        ip_address: Option<String>,
782        user_agent: Option<String>,
783    ) -> Result<String> {
784        self.framework
785            .create_session(user_id, expires_in, ip_address, user_agent)
786            .await
787    }
788
789    /// Fetch a session by ID.
790    pub async fn get(&self, session_id: &str) -> Result<Option<SessionData>> {
791        self.framework.get_session(session_id).await
792    }
793
794    /// Delete a session by ID.
795    pub async fn delete(&self, session_id: &str) -> Result<()> {
796        self.framework.delete_session(session_id).await
797    }
798
799    /// List all sessions owned by a user.
800    pub async fn list_for_user(&self, user_id: &str) -> Result<Vec<SessionData>> {
801        self.framework.storage().list_user_sessions(user_id).await
802    }
803
804    /// List sessions owned by a user, optionally filtering out expired ones.
805    ///
806    /// # Example
807    ///
808    /// ```rust,no_run
809    /// # use auth_framework::prelude::*;
810    /// # use auth_framework::auth_operations::SessionFilter;
811    /// # async fn example(auth: &AuthFramework) -> Result<(), AuthError> {
812    /// let active = auth.sessions()
813    ///     .list_for_user_filtered("user-1", SessionFilter::ActiveOnly)
814    ///     .await?;
815    /// # Ok(())
816    /// # }
817    /// ```
818    pub async fn list_for_user_filtered(
819        &self,
820        user_id: &str,
821        filter: SessionFilter,
822    ) -> Result<Vec<SessionData>> {
823        let sessions = self.framework.storage().list_user_sessions(user_id).await?;
824        if filter.include_inactive() {
825            Ok(sessions)
826        } else {
827            Ok(sessions.into_iter().filter(|s| !s.is_expired()).collect())
828        }
829    }
830
831    /// Remove expired sessions and tokens.
832    pub async fn cleanup_expired(&self) -> Result<()> {
833        self.framework.cleanup_expired_data().await
834    }
835}
836
837// ──────────────────────────────────────────────────────────────────────────────
838// Token operations
839// ──────────────────────────────────────────────────────────────────────────────
840
841/// Builder for [`TokenOperations::create_token`].
842///
843/// Bundles the required token parameters (user ID, auth method) with optional
844/// scopes and lifetime, keeping call sites readable.
845///
846/// # Example
847///
848/// ```rust,no_run
849/// # use auth_framework::prelude::*;
850/// # async fn example(auth: &AuthFramework) -> Result<(), AuthError> {
851/// let token = auth.tokens().create_token(
852///     TokenCreateRequest::new("user-123", "jwt")
853///         .scope("read")
854///         .scope("write")
855///         .lifetime(std::time::Duration::from_secs(7200))
856/// ).await?;
857/// # Ok(())
858/// # }
859/// ```
860#[derive(Debug, Clone)]
861pub struct TokenCreateRequest {
862    user_id: String,
863    method: String,
864    scopes: Vec<String>,
865    lifetime: Option<Duration>,
866}
867
868impl TokenCreateRequest {
869    /// Create a new token request for a user authenticated via `method`.
870    pub fn new(user_id: impl Into<String>, method: impl Into<String>) -> Self {
871        Self {
872            user_id: user_id.into(),
873            method: method.into(),
874            scopes: Vec::new(),
875            lifetime: None,
876        }
877    }
878
879    /// Add a single scope.
880    pub fn scope(mut self, scope: impl Into<String>) -> Self {
881        self.scopes.push(scope.into());
882        self
883    }
884
885    /// Add multiple scopes at once.
886    pub fn scopes<I, S>(mut self, scopes: I) -> Self
887    where
888        I: IntoIterator<Item = S>,
889        S: Into<String>,
890    {
891        self.scopes.extend(scopes.into_iter().map(Into::into));
892        self
893    }
894
895    /// Override the default token lifetime.
896    pub fn lifetime(mut self, duration: Duration) -> Self {
897        self.lifetime = Some(duration);
898        self
899    }
900}
901
902/// Focused token-management operations exposed from [`AuthFramework::tokens`].
903///
904/// # Example
905///
906/// ```rust,no_run
907/// # use auth_framework::prelude::*;
908/// # async fn example(auth: &AuthFramework) -> Result<(), AuthError> {
909/// // Issue a JWT token
910/// let token = auth.tokens().create("user-123", &["read"], "jwt", None).await?;
911///
912/// // Validate
913/// assert!(auth.tokens().validate(&token).await?);
914///
915/// // Refresh
916/// let new_token = auth.tokens().refresh(&token).await?;
917///
918/// // Revoke
919/// auth.tokens().revoke(&new_token).await?;
920/// # Ok(())
921/// # }
922/// ```
923pub struct TokenOperations<'a> {
924    pub(crate) framework: &'a AuthFramework,
925}
926
927impl TokenOperations<'_> {
928    /// Create a new authentication token for a user.
929    ///
930    /// `scopes` accepts any iterator of string-like values, so all of these
931    /// work:
932    ///
933    /// ```rust,ignore
934    /// // Vec<String>
935    /// tokens.create("uid", vec!["read".into()], "jwt", None).await?;
936    /// // Slice of &str
937    /// tokens.create("uid", &["read", "write"], "jwt", None).await?;
938    /// // Empty
939    /// tokens.create("uid", std::iter::empty::<&str>(), "jwt", None).await?;
940    /// ```
941    ///
942    /// # Arguments
943    ///
944    /// * `user_id` — the user to issue a token for
945    /// * `scopes` — permission scopes to embed in the token
946    /// * `method_name` — the auth method that authenticated the user (e.g. `"jwt"`)
947    /// * `lifetime` — custom lifetime, or `None` for the configured default
948    pub async fn create<I, S>(
949        &self,
950        user_id: impl Into<String>,
951        scopes: I,
952        method_name: impl Into<String>,
953        lifetime: Option<Duration>,
954    ) -> Result<AuthToken>
955    where
956        I: IntoIterator<Item = S>,
957        S: AsRef<str>,
958    {
959        let scopes: Vec<String> = scopes.into_iter().map(|s| s.as_ref().to_owned()).collect();
960        self.framework
961            .create_auth_token(user_id, scopes, method_name, lifetime)
962            .await
963    }
964
965    /// Create a token from a [`TokenCreateRequest`].
966    ///
967    /// This is the preferred entry point — it replaces positional `Option`
968    /// parameters with a self-documenting builder.
969    ///
970    /// # Example
971    ///
972    /// ```rust,no_run
973    /// # use auth_framework::prelude::*;
974    /// # async fn example(auth: &AuthFramework) -> Result<(), AuthError> {
975    /// let token = auth.tokens().create_token(
976    ///     TokenCreateRequest::new("user-123", "jwt")
977    ///         .scope("read")
978    ///         .scope("write")
979    /// ).await?;
980    /// # Ok(())
981    /// # }
982    /// ```
983    pub async fn create_token(&self, req: TokenCreateRequest) -> Result<AuthToken> {
984        self.framework
985            .create_auth_token(req.user_id, req.scopes, req.method, req.lifetime)
986            .await
987    }
988
989    /// Validate an authentication token.
990    pub async fn validate(&self, token: &AuthToken) -> Result<bool> {
991        self.framework.validate_token(token).await
992    }
993
994    /// Refresh an authentication token.
995    pub async fn refresh(&self, token: &AuthToken) -> Result<AuthToken> {
996        self.framework.refresh_token(token).await
997    }
998
999    /// Revoke an authentication token.
1000    pub async fn revoke(&self, token: &AuthToken) -> Result<()> {
1001        self.framework.revoke_token(token).await
1002    }
1003
1004    /// List all tokens belonging to a user.
1005    pub async fn list_for_user(&self, user_id: &str) -> Result<Vec<AuthToken>> {
1006        self.framework.list_user_tokens(user_id).await
1007    }
1008
1009    /// Create an API key for a user.
1010    pub async fn create_api_key(
1011        &self,
1012        user_id: &str,
1013        expires_in: Option<Duration>,
1014    ) -> Result<String> {
1015        self.framework.create_api_key(user_id, expires_in).await
1016    }
1017
1018    /// Validate an API key and return the associated user info.
1019    pub async fn validate_api_key(&self, api_key: &str) -> Result<UserInfo> {
1020        self.framework.validate_api_key(api_key).await
1021    }
1022
1023    /// Revoke an API key.
1024    pub async fn revoke_api_key(&self, api_key: &str) -> Result<()> {
1025        self.framework.revoke_api_key(api_key).await
1026    }
1027}
1028
1029// ──────────────────────────────────────────────────────────────────────────────
1030// Authorization operations
1031// ──────────────────────────────────────────────────────────────────────────────
1032
1033/// Focused authorization operations exposed via [`AuthFramework::authorization()`].
1034///
1035/// Provides role-based access control (RBAC), direct permission grants, and
1036/// effective-permission queries.
1037///
1038/// # Example
1039///
1040/// ```rust,no_run
1041/// # async fn example(auth: &auth_framework::AuthFramework) -> auth_framework::Result<()> {
1042/// use auth_framework::permissions::{Permission, Role};
1043/// use auth_framework::tokens::AuthToken;
1044///
1045/// let authz = auth.authorization();
1046/// let token = AuthToken::builder("token_123", "user_123", "access_token").build();
1047///
1048/// // Create a role and assign it to a user
1049/// let mut editor = Role::new("editor");
1050/// editor.add_permission(Permission::new("articles", "edit"));
1051/// authz.create_role(editor).await?;
1052/// authz.assign_role("user_123", "editor").await?;
1053///
1054/// // Check permission via token
1055/// let allowed = authz.check(&token, "edit", "articles").await?;
1056/// # Ok(())
1057/// # }
1058/// ```
1059pub struct AuthorizationOperations<'a> {
1060    pub(crate) framework: &'a AuthFramework,
1061}
1062
1063impl AuthorizationOperations<'_> {
1064    /// Check whether a token grants access to an action on a resource.
1065    pub async fn check(&self, token: &AuthToken, action: &str, resource: &str) -> Result<bool> {
1066        self.framework
1067            .check_permission(token, action, resource)
1068            .await
1069    }
1070
1071    /// Grant a direct permission to a user.
1072    pub async fn grant(&self, user_id: &str, action: &str, resource: &str) -> Result<()> {
1073        self.framework
1074            .grant_permission(user_id, action, resource)
1075            .await
1076    }
1077
1078    /// Revoke a direct permission from a user.
1079    pub async fn revoke(&self, user_id: &str, action: &str, resource: &str) -> Result<()> {
1080        self.framework
1081            .revoke_permission(user_id, action, resource)
1082            .await
1083    }
1084
1085    /// Create a role.
1086    pub async fn create_role(&self, role: Role) -> Result<()> {
1087        self.framework.create_role(role).await
1088    }
1089
1090    /// List all defined roles.
1091    pub async fn list_roles(&self) -> Vec<Role> {
1092        self.framework.list_roles().await
1093    }
1094
1095    /// Fetch a role definition by name.
1096    pub async fn role(&self, role_name: &str) -> Result<Role> {
1097        self.framework.get_role(role_name).await
1098    }
1099
1100    /// Add a permission to an existing role.
1101    pub async fn add_role_permission(
1102        &self,
1103        role_name: &str,
1104        permission: crate::permissions::Permission,
1105    ) -> Result<()> {
1106        self.framework
1107            .add_role_permission(role_name, permission)
1108            .await
1109    }
1110
1111    /// Assign a role to a user.
1112    pub async fn assign_role(&self, user_id: &str, role_name: &str) -> Result<()> {
1113        self.framework.assign_role(user_id, role_name).await
1114    }
1115
1116    /// Remove a role from a user.
1117    pub async fn remove_role(&self, user_id: &str, role_name: &str) -> Result<()> {
1118        self.framework.remove_role(user_id, role_name).await
1119    }
1120
1121    /// Check whether a user currently has a role.
1122    pub async fn has_role(&self, user_id: &str, role_name: &str) -> Result<bool> {
1123        self.framework.user_has_role(user_id, role_name).await
1124    }
1125
1126    /// List effective permissions for a user.
1127    pub async fn effective_permissions(&self, user_id: &str) -> Result<crate::types::Permissions> {
1128        self.framework
1129            .get_effective_permissions(user_id)
1130            .await
1131            .map(crate::types::Permissions)
1132    }
1133
1134    /// List the currently assigned runtime roles for a user.
1135    pub async fn roles_for_user(&self, user_id: &str) -> Result<crate::types::Roles> {
1136        self.framework
1137            .list_user_roles(user_id)
1138            .await
1139            .map(crate::types::Roles)
1140    }
1141}
1142
1143/// Focused maintenance operations exposed via [`AuthFramework::maintenance()`].
1144///
1145/// Backup, restore, and reset authentication state in the configured storage
1146/// backend. All operations support an [`ExecutionMode`] parameter that
1147/// controls whether changes are applied or merely previewed.
1148///
1149/// # Example
1150///
1151/// ```rust,no_run
1152/// # use auth_framework::auth_operations::ExecutionMode;
1153/// # async fn example(auth: &auth_framework::AuthFramework) -> auth_framework::Result<()> {
1154/// let maint = auth.maintenance();
1155///
1156/// // Preview a backup without writing to disk
1157/// let preview = maint.backup("/tmp/auth_backup.json", ExecutionMode::DryRun).await?;
1158/// println!("Would export {} records", preview.manifest.user_count);
1159///
1160/// // Perform the real backup
1161/// let report = maint.backup("/tmp/auth_backup.json", ExecutionMode::Execute).await?;
1162/// # Ok(())
1163/// # }
1164/// ```
1165pub struct MaintenanceOperations<'a> {
1166    pub(crate) framework: &'a AuthFramework,
1167}
1168
1169impl MaintenanceOperations<'_> {
1170    /// Export a logical snapshot to disk.
1171    ///
1172    /// Uses [`ExecutionMode`] for clarity at call sites.
1173    pub async fn backup(&self, output_path: &str, mode: ExecutionMode) -> Result<BackupReport> {
1174        crate::maintenance::backup_to_file(self.framework, output_path, mode.is_dry_run()).await
1175    }
1176
1177    /// Export a logical snapshot to disk (legacy API).
1178    ///
1179    /// Prefer [`backup`](Self::backup) with an [`ExecutionMode`] for
1180    /// self-documenting call sites.
1181    pub async fn backup_to_file(&self, output_path: &str, dry_run: bool) -> Result<BackupReport> {
1182        crate::maintenance::backup_to_file(self.framework, output_path, dry_run).await
1183    }
1184
1185    /// Restore a logical snapshot from disk.
1186    ///
1187    /// Uses [`ExecutionMode`] for clarity at call sites.
1188    pub async fn restore(&self, backup_path: &str, mode: ExecutionMode) -> Result<RestoreReport> {
1189        crate::maintenance::restore_from_file(self.framework, backup_path, mode.is_dry_run()).await
1190    }
1191
1192    /// Restore a logical snapshot from disk (legacy API).
1193    ///
1194    /// Prefer [`restore`](Self::restore) with an [`ExecutionMode`] for
1195    /// self-documenting call sites.
1196    pub async fn restore_from_file(
1197        &self,
1198        backup_path: &str,
1199        dry_run: bool,
1200    ) -> Result<RestoreReport> {
1201        crate::maintenance::restore_from_file(self.framework, backup_path, dry_run).await
1202    }
1203
1204    /// Reset logical authentication state in the configured backend.
1205    ///
1206    /// Uses [`ExecutionMode`] for clarity at call sites.
1207    pub async fn reset_with_mode(&self, mode: ExecutionMode) -> Result<ResetReport> {
1208        crate::maintenance::reset_runtime_data(self.framework, mode.is_dry_run()).await
1209    }
1210
1211    /// Reset logical authentication state in the configured backend (legacy API).
1212    ///
1213    /// Prefer [`reset_with_mode`](Self::reset_with_mode) with an
1214    /// [`ExecutionMode`] for self-documenting call sites.
1215    pub async fn reset(&self, dry_run: bool) -> Result<ResetReport> {
1216        crate::maintenance::reset_runtime_data(self.framework, dry_run).await
1217    }
1218}
1219
1220// ──────────────────────────────────────────────────────────────────────────────
1221// MFA operations
1222// ──────────────────────────────────────────────────────────────────────────────
1223
1224/// Focused multi-factor authentication operations exposed via [`AuthFramework::mfa()`].
1225///
1226/// Covers TOTP, SMS, email challenges, backup codes, and MFA completion
1227/// flows.
1228///
1229/// # Example
1230///
1231/// ```rust,no_run
1232/// # async fn example(auth: &auth_framework::AuthFramework) -> auth_framework::Result<()> {
1233/// let mfa = auth.mfa();
1234///
1235/// // Set up TOTP for a user
1236/// let secret = mfa.generate_totp_secret("user_123").await?;
1237/// let qr_url = mfa.generate_totp_qr_url("user_123", "MyApp", &secret).await?;
1238///
1239/// // Verify a code supplied by the user
1240/// let valid = mfa.verify_totp("user_123", "123456").await?;
1241/// # Ok(())
1242/// # }
1243/// ```
1244pub struct MfaOperations<'a> {
1245    pub(crate) framework: &'a AuthFramework,
1246}
1247
1248impl MfaOperations<'_> {
1249    /// Complete a pending MFA challenge with the provided code.
1250    pub async fn complete(&self, challenge: MfaChallenge, code: &str) -> Result<AuthToken> {
1251        self.framework.complete_mfa(challenge, code).await
1252    }
1253
1254    /// Complete a pending MFA challenge by its ID.
1255    pub async fn complete_by_id(&self, challenge_id: &str, code: &str) -> Result<AuthToken> {
1256        self.framework.complete_mfa_by_id(challenge_id, code).await
1257    }
1258
1259    /// Initiate an SMS-based MFA challenge for a user.
1260    pub async fn initiate_sms(&self, user_id: &str) -> Result<String> {
1261        self.framework.initiate_sms_challenge(user_id).await
1262    }
1263
1264    /// Verify an SMS challenge code.
1265    pub async fn verify_sms(&self, challenge_id: &str, code: &str) -> Result<bool> {
1266        self.framework.verify_sms_code(challenge_id, code).await
1267    }
1268
1269    /// Initiate an email-based MFA challenge for a user.
1270    pub async fn initiate_email(&self, user_id: &str) -> Result<String> {
1271        self.framework.initiate_email_challenge(user_id).await
1272    }
1273
1274    /// Register a phone number for SMS MFA.
1275    pub async fn register_phone(&self, user_id: &str, phone_number: &str) -> Result<()> {
1276        self.framework
1277            .register_phone_number(user_id, phone_number)
1278            .await
1279    }
1280
1281    /// Register an email address for email MFA.
1282    pub async fn register_email(&self, user_id: &str, email: &str) -> Result<()> {
1283        self.framework.register_email(user_id, email).await
1284    }
1285
1286    /// Generate a TOTP secret for a user.
1287    pub async fn generate_totp_secret(&self, user_id: &str) -> Result<String> {
1288        self.framework.generate_totp_secret(user_id).await
1289    }
1290
1291    /// Generate a TOTP QR code provisioning URL.
1292    pub async fn generate_totp_qr_url(
1293        &self,
1294        user_id: &str,
1295        app_name: &str,
1296        secret: &str,
1297    ) -> Result<String> {
1298        self.framework
1299            .generate_totp_qr_code(user_id, app_name, secret)
1300            .await
1301    }
1302
1303    /// Generate the current TOTP code for a secret.
1304    pub async fn generate_totp_code(&self, secret: &str) -> Result<String> {
1305        self.framework.generate_totp_code(secret).await
1306    }
1307
1308    /// Verify a TOTP code for a user.
1309    pub async fn verify_totp(&self, user_id: &str, code: &str) -> Result<bool> {
1310        self.framework.verify_totp_code(user_id, code).await
1311    }
1312
1313    /// Generate backup codes for a user.
1314    pub async fn generate_backup_codes(&self, user_id: &str, count: usize) -> Result<Vec<String>> {
1315        self.framework.generate_backup_codes(user_id, count).await
1316    }
1317}
1318
1319// ──────────────────────────────────────────────────────────────────────────────
1320// Monitoring operations
1321// ──────────────────────────────────────────────────────────────────────────────
1322
1323/// Focused monitoring and health operations exposed via [`AuthFramework::monitoring()`].
1324///
1325/// Health-checks, performance and security metrics, Prometheus export, and
1326/// rate-limit inspection.
1327///
1328/// # Example
1329///
1330/// ```rust,no_run
1331/// # async fn example(auth: &auth_framework::AuthFramework) -> auth_framework::Result<()> {
1332/// let mon = auth.monitoring();
1333///
1334/// let health = mon.health_check().await?;
1335/// let stats  = mon.stats().await?;
1336/// let prom   = mon.prometheus_metrics().await;
1337/// # Ok(())
1338/// # }
1339/// ```
1340pub struct MonitoringOperations<'a> {
1341    pub(crate) framework: &'a AuthFramework,
1342}
1343
1344impl MonitoringOperations<'_> {
1345    /// Perform a comprehensive health check across all subsystems.
1346    ///
1347    /// Returns a map of subsystem name → health result (e.g. `"storage"`,
1348    /// `"token_manager"`, `"rate_limiter"`).
1349    pub async fn health_check(
1350        &self,
1351    ) -> Result<std::collections::HashMap<String, crate::monitoring::HealthCheckResult>> {
1352        self.framework.health_check().await
1353    }
1354
1355    /// Get current performance metrics.
1356    ///
1357    /// Returns a map of metric name → counter value (e.g.
1358    /// `"auth_requests"`, `"auth_successes"`, `"auth_failures"`).
1359    pub async fn performance_metrics(&self) -> std::collections::HashMap<String, u64> {
1360        self.framework.get_performance_metrics().await
1361    }
1362
1363    /// Get aggregated security metrics.
1364    ///
1365    /// Returns a map of metric name → counter value (e.g.
1366    /// `"brute_force_blocked"`, `"rate_limited_requests"`).
1367    pub async fn security_metrics(&self) -> Result<std::collections::HashMap<String, u64>> {
1368        self.framework.get_security_metrics().await
1369    }
1370
1371    /// Export metrics in Prometheus text format.
1372    pub async fn prometheus_metrics(&self) -> String {
1373        self.framework.export_prometheus_metrics().await
1374    }
1375
1376    /// Get authentication statistics.
1377    pub async fn stats(&self) -> Result<AuthStats> {
1378        self.framework.get_stats().await
1379    }
1380
1381    /// Check whether an IP address is within the configured rate limit.
1382    pub async fn check_ip_rate_limit(&self, ip: &str) -> Result<bool> {
1383        self.framework.check_ip_rate_limit(ip).await
1384    }
1385
1386    /// Access the underlying monitoring manager for advanced usage.
1387    pub fn manager(&self) -> Arc<crate::monitoring::MonitoringManager> {
1388        self.framework.monitoring_manager()
1389    }
1390}
1391
1392// ──────────────────────────────────────────────────────────────────────────────
1393// Audit operations
1394// ──────────────────────────────────────────────────────────────────────────────
1395
1396/// Focused audit log operations exposed via [`AuthFramework::audit()`].
1397///
1398/// Query permission audit logs, view permission metrics, and retrieve
1399/// comprehensive security audit statistics.
1400///
1401/// # Example
1402///
1403/// ```rust,no_run
1404/// # async fn example(auth: &auth_framework::AuthFramework) -> auth_framework::Result<()> {
1405/// let audit = auth.audit();
1406///
1407/// // Retrieve recent permission log entries for a specific user
1408/// let logs = audit.permission_logs(Some("user_123"), None, None, Some(50)).await?;
1409///
1410/// // Get security audit statistics
1411/// let stats = audit.security_stats().await?;
1412/// # Ok(())
1413/// # }
1414/// ```
1415pub struct AuditOperations<'a> {
1416    pub(crate) framework: &'a AuthFramework,
1417}
1418
1419impl AuditOperations<'_> {
1420    /// Query permission-related audit log entries using an [`AuditLogQuery`].
1421    ///
1422    /// # Example
1423    ///
1424    /// ```rust,ignore
1425    /// let logs = auth.audit()
1426    ///     .query_permission_logs(
1427    ///         AuditLogQuery::new()
1428    ///             .user("user_123")
1429    ///             .action("read")
1430    ///             .limit(50)
1431    ///     )
1432    ///     .await?;
1433    /// ```
1434    pub async fn query_permission_logs(&self, query: AuditLogQuery) -> Result<Vec<String>> {
1435        self.framework
1436            .get_permission_audit_logs(
1437                query.user_id.as_deref(),
1438                query.action.as_deref(),
1439                query.resource.as_deref(),
1440                query.limit,
1441            )
1442            .await
1443    }
1444
1445    /// Query permission-related audit log entries with optional filters.
1446    ///
1447    /// Prefer [`query_permission_logs`](Self::query_permission_logs) with an
1448    /// [`AuditLogQuery`] for better readability when using multiple filters.
1449    pub async fn permission_logs(
1450        &self,
1451        user_id: Option<&str>,
1452        action: Option<&str>,
1453        resource: Option<&str>,
1454        limit: Option<usize>,
1455    ) -> Result<Vec<String>> {
1456        self.framework
1457            .get_permission_audit_logs(user_id, action, resource, limit)
1458            .await
1459    }
1460
1461    /// Get aggregated permission metrics (role counts, active sessions, checks per hour).
1462    pub async fn permission_metrics(&self) -> Result<std::collections::HashMap<String, u64>> {
1463        self.framework.get_permission_metrics().await
1464    }
1465
1466    /// Get comprehensive security audit statistics.
1467    pub async fn security_stats(&self) -> Result<SecurityAuditStats> {
1468        self.framework.get_security_audit_stats().await
1469    }
1470}
1471#[cfg(test)]
1472mod tests {
1473    use super::*;
1474    use crate::config::AuthConfig;
1475
1476    async fn make_fw() -> AuthFramework {
1477        let config = AuthConfig::new().secret("test_ops_secret_key_32bytes_long!".to_string());
1478        let mut fw = AuthFramework::new(config);
1479        fw.initialize().await.unwrap();
1480        fw
1481    }
1482
1483    // ── UserOperations ──────────────────────────────────────────────────
1484
1485    #[tokio::test]
1486    async fn test_user_ops_register_and_get() {
1487        let fw = make_fw().await;
1488        let uid = fw
1489            .users()
1490            .register("ops_user1", "ops1@test.com", "StrongP@ss1!")
1491            .await
1492            .unwrap();
1493        let info = fw.users().get(&uid).await.unwrap();
1494        assert_eq!(info.username, "ops_user1");
1495    }
1496
1497    #[tokio::test]
1498    async fn test_user_ops_list_empty() {
1499        let fw = make_fw().await;
1500        let list = fw.users().list_with_query(UserListQuery::new().limit(10)).await.unwrap();
1501        assert!(list.is_empty());
1502    }
1503
1504    #[tokio::test]
1505    async fn test_user_ops_exists_by_username() {
1506        let fw = make_fw().await;
1507        fw.users()
1508            .register("exists_u", "exists@test.com", "StrongP@ss1!")
1509            .await
1510            .unwrap();
1511        assert!(fw.users().exists_by_username("exists_u").await.unwrap());
1512        assert!(!fw.users().exists_by_username("nope_u").await.unwrap());
1513    }
1514
1515    #[tokio::test]
1516    async fn test_user_ops_exists_by_email() {
1517        let fw = make_fw().await;
1518        fw.users()
1519            .register("email_u", "email_exists@test.com", "StrongP@ss1!")
1520            .await
1521            .unwrap();
1522        assert!(
1523            fw.users()
1524                .exists_by_email("email_exists@test.com")
1525                .await
1526                .unwrap()
1527        );
1528        assert!(!fw.users().exists_by_email("no@test.com").await.unwrap());
1529    }
1530
1531    #[tokio::test]
1532    async fn test_user_ops_profile() {
1533        let fw = make_fw().await;
1534        let uid = fw
1535            .users()
1536            .register("profile_u", "prof@test.com", "StrongP@ss1!")
1537            .await
1538            .unwrap();
1539        let profile = fw.users().profile(&uid).await.unwrap();
1540        assert_eq!(profile.display_name().unwrap_or_default(), "profile_u");
1541    }
1542
1543    #[tokio::test]
1544    async fn test_user_ops_update_password_and_verify() {
1545        let fw = make_fw().await;
1546        let uid = fw
1547            .users()
1548            .register("pw_user", "pw@test.com", "StrongP@ss1!")
1549            .await
1550            .unwrap();
1551        fw.users()
1552            .update_password("pw_user", "NewStr0ng!Pass")
1553            .await
1554            .unwrap();
1555        assert!(
1556            fw.users()
1557                .verify_password(&uid, "NewStr0ng!Pass")
1558                .await
1559                .unwrap()
1560        );
1561    }
1562
1563    #[tokio::test]
1564    async fn test_user_ops_update_email() {
1565        let fw = make_fw().await;
1566        let uid = fw
1567            .users()
1568            .register("email_upd_u", "old@test.com", "StrongP@ss1!")
1569            .await
1570            .unwrap();
1571        fw.users().update_email(&uid, "new@test.com").await.unwrap();
1572        assert!(fw.users().exists_by_email("new@test.com").await.unwrap());
1573    }
1574
1575    #[tokio::test]
1576    async fn test_user_ops_set_active() {
1577        let fw = make_fw().await;
1578        let uid = fw
1579            .users()
1580            .register("act_u", "act@test.com", "StrongP@ss1!")
1581            .await
1582            .unwrap();
1583        fw.users()
1584            .set_status(&uid, UserStatus::Inactive)
1585            .await
1586            .unwrap();
1587        let info = fw.users().get(&uid).await.unwrap();
1588        assert!(!info.active);
1589    }
1590
1591    #[tokio::test]
1592    async fn test_user_ops_delete() {
1593        let fw = make_fw().await;
1594        fw.users()
1595            .register("del_u", "del@test.com", "StrongP@ss1!")
1596            .await
1597            .unwrap();
1598        fw.users().delete("del_u").await.unwrap();
1599        assert!(!fw.users().exists_by_username("del_u").await.unwrap());
1600    }
1601
1602    #[tokio::test]
1603    async fn test_user_ops_username() {
1604        let fw = make_fw().await;
1605        let uid = fw
1606            .users()
1607            .register("name_u", "name@test.com", "StrongP@ss1!")
1608            .await
1609            .unwrap();
1610        let name = fw.users().username(&uid).await.unwrap();
1611        assert_eq!(name, "name_u");
1612    }
1613
1614    // ── SessionOperations ───────────────────────────────────────────────
1615
1616    #[tokio::test]
1617    async fn test_session_ops_create_get_delete() {
1618        let fw = make_fw().await;
1619        let uid = fw
1620            .users()
1621            .register("sess_u", "sess@test.com", "StrongP@ss1!")
1622            .await
1623            .unwrap();
1624        let sid = fw
1625            .sessions()
1626            .create(&uid, Duration::from_secs(3600), None, None)
1627            .await
1628            .unwrap();
1629        let sess = fw.sessions().get(&sid).await.unwrap();
1630        assert!(sess.is_some());
1631        fw.sessions().delete(&sid).await.unwrap();
1632        assert!(fw.sessions().get(&sid).await.unwrap().is_none());
1633    }
1634
1635    #[tokio::test]
1636    async fn test_session_ops_list_for_user() {
1637        let fw = make_fw().await;
1638        let uid = fw
1639            .users()
1640            .register("sl_u", "sl@test.com", "StrongP@ss1!")
1641            .await
1642            .unwrap();
1643        fw.sessions()
1644            .create(&uid, Duration::from_secs(3600), None, None)
1645            .await
1646            .unwrap();
1647        let list = fw.sessions().list_for_user(&uid).await.unwrap();
1648        assert_eq!(list.len(), 1);
1649    }
1650
1651    #[tokio::test]
1652    async fn test_session_ops_cleanup_expired() {
1653        let fw = make_fw().await;
1654        // Should not error even with no sessions
1655        fw.sessions().cleanup_expired().await.unwrap();
1656    }
1657
1658    // ── TokenOperations ─────────────────────────────────────────────────
1659
1660    #[tokio::test]
1661    async fn test_token_ops_create_validate_revoke() {
1662        let fw = make_fw().await;
1663        let uid = fw
1664            .users()
1665            .register("tok_u", "tok@test.com", "StrongP@ss1!")
1666            .await
1667            .unwrap();
1668        // Create API key instead of auth token—no auth method registration needed
1669        let key = fw.tokens().create_api_key(&uid, None).await.unwrap();
1670        let info = fw.tokens().validate_api_key(&key).await.unwrap();
1671        assert!(!info.id.is_empty());
1672        fw.tokens().revoke_api_key(&key).await.unwrap();
1673    }
1674
1675    #[tokio::test]
1676    async fn test_token_ops_api_key_lifecycle() {
1677        let fw = make_fw().await;
1678        let uid = fw
1679            .users()
1680            .register("apikey_u", "apikey@test.com", "StrongP@ss1!")
1681            .await
1682            .unwrap();
1683        let key = fw.tokens().create_api_key(&uid, None).await.unwrap();
1684        let info = fw.tokens().validate_api_key(&key).await.unwrap();
1685        // API key creates an internal user; just verify it resolves
1686        assert!(!info.id.is_empty());
1687        fw.tokens().revoke_api_key(&key).await.unwrap();
1688        assert!(fw.tokens().validate_api_key(&key).await.is_err());
1689    }
1690
1691    // ── AuthorizationOperations ─────────────────────────────────────────
1692
1693    #[tokio::test]
1694    async fn test_authz_ops_grant_and_check() {
1695        let fw = make_fw().await;
1696        let uid = fw
1697            .users()
1698            .register("authz_u", "authz@test.com", "StrongP@ss1!")
1699            .await
1700            .unwrap();
1701        fw.authorization()
1702            .grant(&uid, "read", "docs")
1703            .await
1704            .unwrap();
1705        // Verify via has_role / effective_permissions rather than via token (no auth method registered)
1706        let perms = fw
1707            .authorization()
1708            .effective_permissions(&uid)
1709            .await
1710            .unwrap();
1711        assert!(perms.iter().any(|p| p.contains("read")));
1712    }
1713
1714    #[tokio::test]
1715    async fn test_authz_ops_role_lifecycle() {
1716        let fw = make_fw().await;
1717        let uid = fw
1718            .users()
1719            .register("role_u", "role@test.com", "StrongP@ss1!")
1720            .await
1721            .unwrap();
1722        fw.authorization().assign_role(&uid, "admin").await.unwrap();
1723        assert!(fw.authorization().has_role(&uid, "admin").await.unwrap());
1724        let roles = fw.authorization().roles_for_user(&uid).await.unwrap();
1725        assert!(roles.contains(&"admin".to_string()));
1726        fw.authorization().remove_role(&uid, "admin").await.unwrap();
1727        assert!(!fw.authorization().has_role(&uid, "admin").await.unwrap());
1728    }
1729
1730    // ── MfaOperations ───────────────────────────────────────────────────
1731
1732    #[tokio::test]
1733    async fn test_mfa_ops_totp_lifecycle() {
1734        let fw = make_fw().await;
1735        let uid = fw
1736            .users()
1737            .register("mfa_u", "mfa@test.com", "StrongP@ss1!")
1738            .await
1739            .unwrap();
1740        let secret = fw.mfa().generate_totp_secret(&uid).await.unwrap();
1741        assert!(!secret.is_empty());
1742        let code = fw.mfa().generate_totp_code(&secret).await.unwrap();
1743        assert_eq!(code.len(), 6);
1744        assert!(fw.mfa().verify_totp(&uid, &code).await.unwrap());
1745    }
1746
1747    #[tokio::test]
1748    async fn test_mfa_ops_backup_codes() {
1749        let fw = make_fw().await;
1750        let uid = fw
1751            .users()
1752            .register("bc_u", "bc@test.com", "StrongP@ss1!")
1753            .await
1754            .unwrap();
1755        let codes = fw.mfa().generate_backup_codes(&uid, 5).await.unwrap();
1756        assert_eq!(codes.len(), 5);
1757    }
1758
1759    #[tokio::test]
1760    async fn test_mfa_ops_sms_lifecycle() {
1761        let fw = make_fw().await;
1762        let uid = fw
1763            .users()
1764            .register("smsop_u", "smsop@test.com", "StrongP@ss1!")
1765            .await
1766            .unwrap();
1767        fw.mfa().register_phone(&uid, "+12345678901").await.unwrap();
1768        let cid = fw.mfa().initiate_sms(&uid).await.unwrap();
1769        assert!(!cid.is_empty());
1770    }
1771
1772    #[tokio::test]
1773    async fn test_mfa_ops_email_lifecycle() {
1774        let fw = make_fw().await;
1775        let uid = fw
1776            .users()
1777            .register("emop_u", "emop@test.com", "StrongP@ss1!")
1778            .await
1779            .unwrap();
1780        fw.mfa()
1781            .register_email(&uid, "emop@test.com")
1782            .await
1783            .unwrap();
1784        let cid = fw.mfa().initiate_email(&uid).await.unwrap();
1785        assert!(!cid.is_empty());
1786    }
1787
1788    // ── MonitoringOperations ────────────────────────────────────────────
1789
1790    #[tokio::test]
1791    async fn test_monitoring_ops_health_check() {
1792        let fw = make_fw().await;
1793        let health = fw.monitoring().health_check().await.unwrap();
1794        assert!(!health.is_empty());
1795    }
1796
1797    #[tokio::test]
1798    async fn test_monitoring_ops_performance_metrics() {
1799        let fw = make_fw().await;
1800        let _metrics = fw.monitoring().performance_metrics().await;
1801    }
1802
1803    #[tokio::test]
1804    async fn test_monitoring_ops_stats() {
1805        let fw = make_fw().await;
1806        let stats = fw.monitoring().stats().await.unwrap();
1807        assert_eq!(stats.active_sessions, 0);
1808    }
1809
1810    #[tokio::test]
1811    async fn test_monitoring_ops_prometheus() {
1812        let fw = make_fw().await;
1813        let prom = fw.monitoring().prometheus_metrics().await;
1814        // Just verify it returns valid-looking metrics text
1815        assert!(!prom.is_empty());
1816    }
1817
1818    // ── AdminOperations ─────────────────────────────────────────────────
1819
1820    #[tokio::test]
1821    async fn test_admin_ops_role_inheritance() {
1822        let fw = make_fw().await;
1823        // Default roles include "admin" and "user" — use those
1824        fw.admin()
1825            .set_role_inheritance("user", "admin")
1826            .await
1827            .unwrap();
1828    }
1829
1830    #[tokio::test]
1831    async fn test_admin_ops_abac_policy() {
1832        let fw = make_fw().await;
1833        fw.admin()
1834            .create_abac_policy("ip_allow", "IP allowlist policy")
1835            .await
1836            .unwrap();
1837    }
1838
1839    #[tokio::test]
1840    async fn test_admin_ops_user_attributes() {
1841        let fw = make_fw().await;
1842        let uid = fw
1843            .users()
1844            .register("attr_u", "attr@test.com", "StrongP@ss1!")
1845            .await
1846            .unwrap();
1847        fw.admin()
1848            .map_user_attribute(&uid, "department", "engineering")
1849            .await
1850            .unwrap();
1851        let val = fw
1852            .admin()
1853            .get_user_attribute(&uid, "department")
1854            .await
1855            .unwrap();
1856        assert_eq!(val.as_deref(), Some("engineering"));
1857    }
1858
1859    #[tokio::test]
1860    async fn test_admin_ops_delegation() {
1861        let fw = make_fw().await;
1862        let uid1 = fw
1863            .users()
1864            .register("del_from", "delf@test.com", "StrongP@ss1!")
1865            .await
1866            .unwrap();
1867        let uid2 = fw
1868            .users()
1869            .register("del_to", "delt@test.com", "StrongP@ss1!")
1870            .await
1871            .unwrap();
1872        fw.authorization()
1873            .grant(&uid1, "write", "report")
1874            .await
1875            .unwrap();
1876        fw.admin()
1877            .delegate_permission(&uid1, &uid2, "write", "report", Duration::from_secs(3600))
1878            .await
1879            .unwrap();
1880    }
1881
1882    // ── MaintenanceOperations ───────────────────────────────────────────
1883
1884    #[tokio::test]
1885    async fn test_maintenance_ops_backup_dry_run() {
1886        let fw = make_fw().await;
1887        let report = fw
1888            .maintenance()
1889            .backup_to_file("test_backup.json", true)
1890            .await
1891            .unwrap();
1892        assert!(report.dry_run);
1893    }
1894
1895    #[tokio::test]
1896    async fn test_maintenance_ops_reset_dry_run() {
1897        let fw = make_fw().await;
1898        let report = fw.maintenance().reset(true).await.unwrap();
1899        assert!(report.dry_run);
1900    }
1901
1902    // ── AuditOperations ─────────────────────────────────────────────────
1903
1904    #[tokio::test]
1905    async fn test_audit_ops_permission_logs() {
1906        let fw = make_fw().await;
1907        let logs = fw
1908            .audit()
1909            .permission_logs(None, None, None, Some(10))
1910            .await
1911            .unwrap();
1912        assert!(logs.is_empty()); // no activity yet
1913    }
1914
1915    #[tokio::test]
1916    async fn test_audit_ops_permission_metrics() {
1917        let fw = make_fw().await;
1918        let metrics = fw.audit().permission_metrics().await.unwrap();
1919        assert!(!metrics.is_empty());
1920    }
1921
1922    #[tokio::test]
1923    async fn test_audit_ops_security_stats() {
1924        let fw = make_fw().await;
1925        let stats = fw.audit().security_stats().await.unwrap();
1926        assert_eq!(stats.failed_logins_24h, 0);
1927    }
1928}
1929// ──────────────────────────────────────────────────────────────────────────────
1930// Admin operations
1931// ──────────────────────────────────────────────────────────────────────────────
1932
1933/// Focused advanced administration operations exposed from [`AuthFramework::admin`].
1934///
1935/// These operations go beyond the everyday [`AuthorizationOperations`] surface and cover
1936/// ABAC policy management, permission delegation, role inheritance, resource registration,
1937/// and attribute-based access control.
1938pub struct AdminOperations<'a> {
1939    pub(crate) framework: &'a AuthFramework,
1940}
1941
1942impl AdminOperations<'_> {
1943    /// Define a parent–child role inheritance relationship.
1944    pub async fn set_role_inheritance(&self, child_role: &str, parent_role: &str) -> Result<()> {
1945        self.framework
1946            .set_role_inheritance(child_role, parent_role)
1947            .await
1948    }
1949
1950    /// Create an ABAC policy.
1951    pub async fn create_abac_policy(&self, name: &str, description: &str) -> Result<()> {
1952        self.framework.create_abac_policy(name, description).await
1953    }
1954
1955    /// Map a user attribute used in ABAC policy evaluation.
1956    pub async fn map_user_attribute(
1957        &self,
1958        user_id: &str,
1959        attribute: &str,
1960        value: &str,
1961    ) -> Result<()> {
1962        self.framework
1963            .map_user_attribute(user_id, attribute, value)
1964            .await
1965    }
1966
1967    /// Set multiple user attributes in one call.
1968    ///
1969    /// This is a convenience wrapper around [`map_user_attribute`](Self::map_user_attribute)
1970    /// for setting several ABAC attributes at once.
1971    ///
1972    /// # Example
1973    ///
1974    /// ```rust,no_run
1975    /// # use auth_framework::prelude::*;
1976    /// # async fn example(auth: &AuthFramework) -> Result<(), AuthError> {
1977    /// auth.admin().set_user_attributes("user-1", &[
1978    ///     ("department", "engineering"),
1979    ///     ("clearance", "top-secret"),
1980    ///     ("location", "us-west-2"),
1981    /// ]).await?;
1982    /// # Ok(())
1983    /// # }
1984    /// ```
1985    pub async fn set_user_attributes(
1986        &self,
1987        user_id: &str,
1988        attributes: &[(&str, &str)],
1989    ) -> Result<()> {
1990        for &(attribute, value) in attributes {
1991            self.framework
1992                .map_user_attribute(user_id, attribute, value)
1993                .await?;
1994        }
1995        Ok(())
1996    }
1997
1998    /// Get a user attribute value.
1999    pub async fn get_user_attribute(
2000        &self,
2001        user_id: &str,
2002        attribute: &str,
2003    ) -> Result<Option<String>> {
2004        self.framework.get_user_attribute(user_id, attribute).await
2005    }
2006
2007    /// Check a permission using dynamic ABAC context evaluation.
2008    ///
2009    /// Prefer [`check_dynamic_permission_with_context`](Self::check_dynamic_permission_with_context)
2010    /// with a [`PermissionContext`] for a more readable API.
2011    pub async fn check_dynamic_permission(
2012        &self,
2013        user_id: &str,
2014        action: &str,
2015        resource: &str,
2016        context: std::collections::HashMap<String, String>,
2017    ) -> Result<bool> {
2018        self.framework
2019            .check_dynamic_permission(user_id, action, resource, context)
2020            .await
2021    }
2022
2023    /// Check a permission using dynamic ABAC context evaluation with a
2024    /// [`PermissionContext`].
2025    ///
2026    /// # Example
2027    ///
2028    /// ```rust,ignore
2029    /// use auth_framework::auth_operations::PermissionContext;
2030    ///
2031    /// let ctx = PermissionContext::new()
2032    ///     .with_attribute("ip_location", "office")
2033    ///     .with_attribute("device_type", "trusted");
2034    ///
2035    /// let allowed = auth.admin()
2036    ///     .check_dynamic_permission_with_context("user_123", "read", "docs", ctx)
2037    ///     .await?;
2038    /// ```
2039    pub async fn check_dynamic_permission_with_context(
2040        &self,
2041        user_id: &str,
2042        action: &str,
2043        resource: &str,
2044        context: PermissionContext,
2045    ) -> Result<bool> {
2046        self.framework
2047            .check_dynamic_permission(user_id, action, resource, context.into_attributes())
2048            .await
2049    }
2050
2051    /// Register a resource in the permission system.
2052    pub async fn create_resource(&self, resource: &str) -> Result<()> {
2053        self.framework.create_resource(resource).await
2054    }
2055
2056    /// Delegate a permission from one user to another using a [`DelegationRequest`].
2057    ///
2058    /// # Example
2059    ///
2060    /// ```rust,ignore
2061    /// auth.admin()
2062    ///     .delegate(
2063    ///         DelegationRequest::new("admin_1", "user_2", "write", "reports")
2064    ///             .duration(Duration::from_secs(3600))
2065    ///     )
2066    ///     .await?;
2067    /// ```
2068    pub async fn delegate(&self, req: DelegationRequest) -> Result<()> {
2069        self.framework
2070            .delegate_permission(
2071                &req.delegator_id,
2072                &req.delegatee_id,
2073                &req.action,
2074                &req.resource,
2075                req.duration,
2076            )
2077            .await
2078    }
2079
2080    /// Delegate a permission from one user to another for a limited duration.
2081    ///
2082    /// Prefer [`delegate`](Self::delegate) with a [`DelegationRequest`] for
2083    /// better readability.
2084    pub async fn delegate_permission(
2085        &self,
2086        delegator_id: &str,
2087        delegatee_id: &str,
2088        action: &str,
2089        resource: &str,
2090        duration: Duration,
2091    ) -> Result<()> {
2092        self.framework
2093            .delegate_permission(delegator_id, delegatee_id, action, resource, duration)
2094            .await
2095    }
2096
2097    /// List currently active permission delegations for a user.
2098    pub async fn active_delegations(&self, user_id: &str) -> Result<Vec<String>> {
2099        self.framework.get_active_delegations(user_id).await
2100    }
2101}