Skip to main content

backbone_auth/
traits.rs

1//! Trait definitions for authentication system integration
2//!
3//! This module provides **generic traits** for authentication.
4//! Modules can implement these traits with their own domain entities.
5//!
6//! ## Generic Design
7//!
8//! Instead of hardcoded entity structs, this module uses traits:
9//! - `AuthenticatableUser` - Trait for user entities that can be authenticated
10//! - `UserRepository` - Generic repository trait for user operations
11//!
12//! ## Usage
13//!
14//! ```rust,ignore
15//! // Module implements trait for its domain User entity
16//! impl AuthenticatableUser for MyUser {
17//!     fn id(&self) -> &Uuid { &self.id }
18//!     fn email(&self) -> &str { &self.email }
19//!     fn password_hash(&self) -> &str { &self.password_hash }
20//!     // ... other methods
21//! }
22//! ```
23
24use anyhow::Result;
25use async_trait::async_trait;
26use serde::{Serialize, Deserialize};
27use uuid::Uuid;
28use chrono::{DateTime, Utc};
29
30// ============================================================================
31// GENERIC TRAITS - Modules implement these with their domain entities
32// ============================================================================
33
34/// Trait for user entities that can be authenticated
35///
36/// Implement this trait for your domain User entity to use with authentication.
37pub trait AuthenticatableUser: Clone + Send + Sync {
38    /// User ID
39    fn id(&self) -> &Uuid;
40
41    /// User email address
42    fn email(&self) -> &str;
43
44    /// Password hash for verification
45    fn password_hash(&self) -> &str;
46
47    /// Whether the user account is active
48    fn is_active(&self) -> bool;
49
50    /// Whether the user account is locked
51    fn is_locked(&self) -> bool;
52
53    /// User roles (e.g., ["admin", "user"])
54    fn roles(&self) -> &[String];
55
56    /// Whether 2FA is enabled
57    fn two_factor_enabled(&self) -> bool { false }
58
59    /// 2FA methods available to user
60    fn two_factor_methods(&self) -> &[String] { &[] }
61
62    /// Account expiration timestamp
63    fn account_expires_at(&self) -> Option<DateTime<Utc>> { None }
64
65    /// Whether user must change password
66    fn requires_password_change(&self) -> bool { false }
67
68    /// Last login timestamp
69    fn last_login_at(&self) -> Option<DateTime<Utc>> { None }
70
71    /// Number of failed login attempts
72    fn failed_login_attempts(&self) -> u32 { 0 }
73
74    /// When account lockout expires
75    fn locked_until(&self) -> Option<DateTime<Utc>> { None }
76}
77
78// ============================================================================
79// DEFAULT IMPLEMENTATIONS - Simple structs for testing/demos
80// ============================================================================
81
82/// Simple user struct for default authentication implementation
83///
84/// For production, modules should implement `AuthenticatableUser` trait
85/// for their own domain User entity.
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct SimpleUser {
88    pub id: Uuid,
89    pub email: String,
90    pub password_hash: String,
91    pub is_active: bool,
92    pub is_locked: bool,
93    pub roles: Vec<String>,
94    pub two_factor_enabled: bool,
95    pub two_factor_methods: Vec<String>,
96    pub account_expires_at: Option<DateTime<Utc>>,
97    pub requires_password_change: bool,
98    pub last_login_at: Option<DateTime<Utc>>,
99    pub failed_login_attempts: u32,
100    pub locked_until: Option<DateTime<Utc>>,
101    pub created_at: DateTime<Utc>,
102    pub updated_at: DateTime<Utc>,
103}
104
105impl AuthenticatableUser for SimpleUser {
106    fn id(&self) -> &Uuid { &self.id }
107    fn email(&self) -> &str { &self.email }
108    fn password_hash(&self) -> &str { &self.password_hash }
109    fn is_active(&self) -> bool { self.is_active }
110    fn is_locked(&self) -> bool { self.is_locked }
111    fn roles(&self) -> &[String] { &self.roles }
112    fn two_factor_enabled(&self) -> bool { self.two_factor_enabled }
113    fn two_factor_methods(&self) -> &[String] { &self.two_factor_methods }
114    fn account_expires_at(&self) -> Option<DateTime<Utc>> { self.account_expires_at }
115    fn requires_password_change(&self) -> bool { self.requires_password_change }
116    fn last_login_at(&self) -> Option<DateTime<Utc>> { self.last_login_at }
117    fn failed_login_attempts(&self) -> u32 { self.failed_login_attempts }
118    fn locked_until(&self) -> Option<DateTime<Utc>> { self.locked_until }
119}
120
121// ============================================================================
122// BACKWARDS COMPATIBILITY - Type alias for existing code
123// ============================================================================
124
125/// Type alias for backwards compatibility
126///
127/// DEPRECATED: Use `SimpleUser` or implement `AuthenticatableUser` trait.
128pub type User = SimpleUser;
129
130/// Refresh token claims for token refresh functionality
131#[derive(Debug, Clone, Serialize, Deserialize)]
132pub struct RefreshTokenClaims {
133    pub sub: String,
134    pub exp: usize,
135    pub iat: usize,
136    pub iss: String,
137    pub token_type: String,
138}
139
140/// Generic user repository trait for database operations
141///
142/// The generic type `U` must implement `AuthenticatableUser`.
143#[async_trait]
144pub trait UserRepository<U: AuthenticatableUser = SimpleUser>: Send + Sync {
145    /// Find user by email address
146    async fn find_by_email(&self, email: &str) -> Result<Option<U>>;
147
148    /// Find user by ID
149    async fn find_by_id(&self, id: &Uuid) -> Result<Option<U>>;
150
151    /// Create new user
152    async fn create(&self, user: &U) -> Result<U>;
153
154    /// Update user
155    async fn update(&self, user: &U) -> Result<U>;
156
157    /// Update user's last login timestamp
158    async fn update_last_login(&self, user_id: &Uuid) -> Result<()>;
159
160    /// Increment failed login attempts
161    async fn increment_failed_attempts(&self, user_id: &Uuid) -> Result<()>;
162
163    /// Reset failed login attempts
164    async fn reset_failed_attempts(&self, user_id: &Uuid) -> Result<()>;
165
166    /// Lock user account
167    async fn lock_account(&self, user_id: &Uuid, locked_until: Option<DateTime<Utc>>) -> Result<()>;
168
169    /// Unlock user account
170    async fn unlock_account(&self, user_id: &Uuid) -> Result<()>;
171
172    /// Check if user exists by email
173    async fn exists_by_email(&self, email: &str) -> Result<bool>;
174}
175
176/// Security service trait for authentication security features
177#[async_trait]
178pub trait SecurityService: Send + Sync {
179    /// Check rate limiting for authentication attempts
180    async fn check_rate_limit(&self, email: &str, ip_address: Option<&str>) -> Result<()>;
181
182    /// Log failed authentication attempt for security monitoring
183    async fn log_failed_auth_attempt(&self, user_id: &Uuid, ip_address: Option<&str>) -> Result<()>;
184
185    /// Log successful authentication for audit trail
186    async fn log_successful_auth(&self, user_id: &Uuid, ip_address: Option<&str>) -> Result<()>;
187
188    /// Analyze login attempt for security threats
189    async fn analyze_login_attempt(
190        &self,
191        user_id: &Uuid,
192        device_info: &Option<DeviceInfo>,
193        ip_address: Option<&str>
194    ) -> Result<SecurityFlags>;
195
196    /// Generate password reset token
197    async fn generate_password_reset_token(&self, user_id: &Uuid) -> Result<String>;
198
199    /// Validate password reset token
200    async fn validate_password_reset_token(&self, token: &str) -> Result<Option<Uuid>>;
201
202    /// Send security alert (new device, suspicious activity, etc.)
203    async fn send_security_alert(&self, user_id: &Uuid, alert_type: SecurityAlertType, details: &str) -> Result<()>;
204}
205
206/// Device information for security tracking
207#[derive(Debug, Clone, Serialize, Deserialize)]
208pub struct DeviceInfo {
209    pub device_id: Option<String>,
210    pub device_type: String, // "web", "mobile", "api"
211    pub platform: Option<String>, // "ios", "android", "windows", etc.
212    pub user_agent: Option<String>,
213    pub fingerprint: Option<String>,
214}
215
216/// Security flags for authentication result
217#[derive(Debug, Clone, Default, Serialize, Deserialize)]
218pub struct SecurityFlags {
219    pub new_device: bool,
220    pub new_location: bool,
221    pub suspicious_activity: bool,
222    pub requires_password_change: bool,
223    pub risk_score: f32, // 0.0 to 1.0
224}
225
226/// Security alert types
227#[derive(Debug, Clone, Serialize, Deserialize)]
228pub enum SecurityAlertType {
229    NewDeviceLogin,
230    NewLocationLogin,
231    SuspiciousActivity,
232    AccountLocked,
233    PasswordReset,
234    MultipleFailedAttempts,
235}
236
237/// Authentication context for enhanced security
238#[derive(Debug, Clone)]
239pub struct AuthContext {
240    pub ip_address: Option<String>,
241    pub user_agent: Option<String>,
242    pub device_fingerprint: Option<String>,
243    pub timestamp: DateTime<Utc>,
244    pub session_id: Option<String>,
245}
246
247impl Default for AuthContext {
248    fn default() -> Self {
249        Self {
250            ip_address: None,
251            user_agent: None,
252            device_fingerprint: None,
253            timestamp: Utc::now(),
254            session_id: None,
255        }
256    }
257}
258
259/// Password strength requirements
260#[derive(Debug, Clone, Serialize, Deserialize)]
261pub struct PasswordPolicy {
262    pub min_length: usize,
263    pub max_length: usize,
264    pub require_uppercase: bool,
265    pub require_lowercase: bool,
266    pub require_numbers: bool,
267    pub require_special_chars: bool,
268    pub forbidden_patterns: Vec<String>,
269    pub common_passwords: Vec<String>,
270}
271
272impl Default for PasswordPolicy {
273    fn default() -> Self {
274        Self {
275            min_length: 8,
276            max_length: 128,
277            require_uppercase: true,
278            require_lowercase: true,
279            require_numbers: true,
280            require_special_chars: false,
281            forbidden_patterns: vec![
282                "password".to_string(),
283                "123456".to_string(),
284                "qwerty".to_string(),
285            ],
286            common_passwords: vec![
287                "password".to_string(),
288                "123456".to_string(),
289                "123456789".to_string(),
290                "qwerty".to_string(),
291                "abc123".to_string(),
292                "password123".to_string(),
293                "admin".to_string(),
294                "letmein".to_string(),
295                "welcome".to_string(),
296                "monkey".to_string(),
297            ],
298        }
299    }
300}
301
302/// Two-factor authentication methods
303#[derive(Debug, Clone, Serialize, Deserialize)]
304pub enum TwoFactorMethod {
305    TOTP, // Time-based One-Time Password
306    SMS,  // SMS verification
307    Email, // Email verification
308    BackupCode, // Backup codes
309}
310
311/// Two-factor authentication challenge
312#[derive(Debug, Clone)]
313pub struct TwoFactorChallenge {
314    pub user_id: Uuid,
315    pub method: TwoFactorMethod,
316    pub challenge: String,
317    pub expires_at: DateTime<Utc>,
318}
319
320/// Password reset request
321#[derive(Debug, Clone)]
322pub struct PasswordResetRequest {
323    pub email: String,
324    pub context: AuthContext,
325}
326
327/// Password reset confirmation
328#[derive(Debug, Clone)]
329pub struct PasswordResetConfirmation {
330    pub token: String,
331    pub new_password: String,
332    pub context: AuthContext,
333}
334
335/// Enhanced authentication request
336#[derive(Debug, Clone)]
337pub struct AuthRequest {
338    pub email: String,
339    pub password: String,
340    pub remember_me: Option<bool>,
341    pub device_info: Option<DeviceInfo>,
342    pub ip_address: Option<String>,
343    pub user_agent: Option<String>,
344}
345
346/// Enhanced authentication result with security info
347#[derive(Debug, Clone)]
348pub struct AuthResultEnhanced {
349    pub user_id: Uuid,
350    pub token: String,
351    pub refresh_token: Option<String>,
352    pub expires_at: DateTime<Utc>,
353    pub requires_2fa: bool,
354    pub security_flags: SecurityFlags,
355}