avl_auth/
client.rs

1//! Main AuthClient implementation
2
3use crate::api_keys::ApiKeyManager;
4use crate::audit::AuditManager;
5use crate::config::Config;
6use crate::crypto::CryptoManager;
7use crate::error::{AuthError, Result};
8use crate::jwt::{JwtConfig, JwtManager};
9use crate::mfa::MfaManager;
10use crate::models::*;
11use crate::oauth2::OAuth2Manager;
12use crate::password::{PasswordManager, PasswordPolicy};
13use crate::permissions::PermissionManager;
14use crate::risk::{RiskConfig, RiskEngine};
15use crate::session::{SessionConfig, SessionManager};
16use chrono::{Duration, Utc};
17use std::collections::HashMap;
18use std::sync::Arc;
19use tokio::sync::RwLock;
20use uuid::Uuid;
21
22pub struct AuthClient {
23    config: Config,
24    jwt: Arc<JwtManager>,
25    password: Arc<PasswordManager>,
26    oauth2: Arc<OAuth2Manager>,
27    mfa: Arc<MfaManager>,
28    permissions: Arc<PermissionManager>,
29    sessions: Arc<SessionManager>,
30    api_keys: Arc<ApiKeyManager>,
31    risk: Arc<RiskEngine>,
32    audit: Arc<AuditManager>,
33    crypto: Arc<CryptoManager>,
34    users: Arc<RwLock<HashMap<Uuid, User>>>,
35}
36
37impl AuthClient {
38    pub async fn new(config: Config) -> Result<Self> {
39        config.validate()?;
40
41        let jwt_config = JwtConfig {
42            algorithm: parse_algorithm(&config.jwt.algorithm)
43                .map_err(|e| AuthError::ConfigError(e))?,
44            issuer: config.jwt.issuer.clone(),
45            audience: config.jwt.audience.clone(),
46            access_token_ttl: chrono::Duration::from_std(config.jwt.access_token_ttl)
47                .map_err(|e| AuthError::ConfigError(e.to_string()))?,
48            refresh_token_ttl: chrono::Duration::from_std(config.jwt.refresh_token_ttl)
49                .map_err(|e| AuthError::ConfigError(e.to_string()))?,
50        };
51
52        let jwt = Arc::new(JwtManager::new(
53            jwt_config,
54            &config.jwt.private_key,
55            &config.jwt.public_key,
56        )?);
57
58        let password_policy = PasswordPolicy {
59            min_length: config.password.min_length,
60            require_uppercase: config.password.require_uppercase,
61            require_lowercase: config.password.require_lowercase,
62            require_numbers: config.password.require_numbers,
63            require_special: config.password.require_special,
64            password_history: config.password.password_history,
65        };
66
67        let password = Arc::new(PasswordManager::new(
68            password_policy,
69            config.password.argon2_memory_cost,
70            config.password.argon2_time_cost,
71            config.password.argon2_parallelism,
72        )?);
73
74        let oauth2 = Arc::new(OAuth2Manager::new());
75        for provider in &config.oauth2_providers {
76            oauth2.register_provider(provider.clone()).await?;
77        }
78
79        let mfa = Arc::new(MfaManager::new(
80            config.mfa.totp_issuer.clone(),
81            config.mfa.totp_period,
82            config.mfa.totp_digits,
83        ));
84
85        let permissions = Arc::new(PermissionManager::new());
86
87        let session_config = SessionConfig {
88            idle_timeout: chrono::Duration::from_std(config.session.idle_timeout)
89                .map_err(|e| AuthError::ConfigError(e.to_string()))?,
90            absolute_timeout: chrono::Duration::from_std(config.session.absolute_timeout)
91                .map_err(|e| AuthError::ConfigError(e.to_string()))?,
92            max_concurrent_sessions: config.session.max_concurrent_sessions,
93            device_binding: config.session.device_binding,
94            ip_binding: config.session.ip_binding,
95        };
96
97        let sessions = Arc::new(SessionManager::new(session_config));
98
99        let api_keys = Arc::new(ApiKeyManager::new());
100
101        let risk_config = RiskConfig {
102            mfa_threshold: config.risk.mfa_threshold,
103            block_threshold: config.risk.block_threshold,
104            geo_velocity_enabled: config.risk.geo_velocity_check,
105            max_travel_speed_kmh: config.risk.max_travel_speed,
106        };
107
108        let risk = Arc::new(RiskEngine::new(risk_config));
109
110        let audit = Arc::new(AuditManager::new(90)); // 90-day retention
111
112        let crypto = Arc::new(CryptoManager::new());
113
114        Ok(Self {
115            config,
116            jwt,
117            password,
118            oauth2,
119            mfa,
120            permissions,
121            sessions,
122            api_keys,
123            risk,
124            audit,
125            crypto,
126            users: Arc::new(RwLock::new(HashMap::new())),
127        })
128    }
129
130    // ==================== User Management ====================
131
132    pub async fn register(&self, email: String, password: String) -> Result<Uuid> {
133        // Validate email
134        if !email.contains('@') {
135            return Err(AuthError::InvalidPassword("Invalid email format".to_string()));
136        }
137
138        // Check if user already exists
139        let users = self.users.read().await;
140        if users.values().any(|u| u.email == email) {
141            return Err(AuthError::UserAlreadyExists(email));
142        }
143        drop(users);
144
145        // Hash password
146        let password_hash = self.password.hash_password(&password)?;
147
148        let user = User {
149            id: Uuid::new_v4(),
150            email: email.clone(),
151            email_verified: false,
152            password_hash,
153            display_name: None,
154            avatar_url: None,
155            roles: vec!["user".to_string()],
156            permissions: vec![],
157            metadata: HashMap::new(),
158            mfa_enabled: false,
159            mfa_secret: None,
160            webauthn_credentials: vec![],
161            created_at: Utc::now(),
162            updated_at: Utc::now(),
163            last_login_at: None,
164            login_count: 0,
165            failed_login_attempts: 0,
166            locked_until: None,
167            password_changed_at: Utc::now(),
168            status: UserStatus::Active,
169        };
170
171        let user_id = user.id;
172
173        let mut users = self.users.write().await;
174        users.insert(user_id, user);
175
176        self.audit.log(
177            Some(user_id),
178            None,
179            "user.register".to_string(),
180            "user".to_string(),
181            AuditResult::Success,
182            None,
183            None,
184            HashMap::new(),
185            0,
186        ).await;
187
188        tracing::info!(user_id = %user_id, email = %email, "User registered");
189
190        Ok(user_id)
191    }
192
193    pub async fn login(&self, credentials: Credentials) -> Result<Session> {
194        let users = self.users.read().await;
195
196        let user = users
197            .values()
198            .find(|u| u.email == credentials.email)
199            .cloned()
200            .ok_or(AuthError::InvalidCredentials)?;
201
202        drop(users);
203
204        // Check if account is locked
205        if let Some(locked_until) = user.locked_until {
206            if Utc::now() < locked_until {
207                return Err(AuthError::AccountLocked(
208                    format!("Account locked until {}", locked_until)
209                ));
210            }
211        }
212
213        // Verify password
214        let password_valid = self.password.verify_password(&credentials.password, &user.password_hash)?;
215
216        if !password_valid {
217            self.handle_failed_login(&user.id).await?;
218
219            self.audit.log(
220                Some(user.id),
221                None,
222                "user.login".to_string(),
223                "session".to_string(),
224                AuditResult::Failure,
225                credentials.ip_address,
226                None,
227                HashMap::new(),
228                50,
229            ).await;
230
231            return Err(AuthError::InvalidCredentials);
232        }
233
234        // Risk assessment
235        let risk_assessment = self.risk.assess_risk(
236            &user,
237            credentials.ip_address,
238            credentials.device_id.as_deref(),
239            None,
240        ).await?;
241
242        match risk_assessment.recommended_action {
243            RiskAction::Deny => {
244                self.audit.log(
245                    Some(user.id),
246                    None,
247                    "user.login".to_string(),
248                    "session".to_string(),
249                    AuditResult::Blocked,
250                    credentials.ip_address,
251                    None,
252                    HashMap::new(),
253                    risk_assessment.score,
254                ).await;
255
256                return Err(AuthError::SuspiciousActivity(
257                    "Login blocked due to high risk score".to_string()
258                ));
259            }
260            RiskAction::RequireMfa if !user.mfa_enabled => {
261                return Err(AuthError::MfaRequired);
262            }
263            _ => {}
264        }
265
266        // Update behavior profile
267        self.risk.update_behavior_profile(
268            &user.id,
269            credentials.ip_address,
270            credentials.device_id.clone(),
271            true,
272        ).await;
273
274        // Create JWT claims
275        let claims = self.jwt.create_claims(
276            user.id,
277            user.email.clone(),
278            user.roles.clone(),
279            user.permissions.clone(),
280            Uuid::new_v4(),
281            vec!["*".to_string()],
282            credentials.device_id.clone(),
283        );
284
285        let access_token = self.jwt.create_token(&claims).await?;
286        let refresh_token = self.crypto.generate_token(32);
287
288        // Create session
289        let session = self.sessions.create_session(
290            user.id,
291            access_token,
292            refresh_token,
293            chrono::Duration::from_std(self.config.jwt.access_token_ttl)
294                .map_err(|e| AuthError::ConfigError(e.to_string()))?,
295            chrono::Duration::from_std(self.config.jwt.refresh_token_ttl)
296                .map_err(|e| AuthError::ConfigError(e.to_string()))?,
297            credentials.device_id,
298            credentials.ip_address,
299            None,
300            vec!["*".to_string()],
301        ).await?;
302
303        // Update user
304        let mut users = self.users.write().await;
305        if let Some(u) = users.get_mut(&user.id) {
306            u.last_login_at = Some(Utc::now());
307            u.login_count += 1;
308            u.failed_login_attempts = 0;
309        }
310
311        self.audit.log(
312            Some(user.id),
313            Some(session.id),
314            "user.login".to_string(),
315            "session".to_string(),
316            AuditResult::Success,
317            credentials.ip_address,
318            None,
319            HashMap::new(),
320            risk_assessment.score,
321        ).await;
322
323        Ok(session)
324    }
325
326    async fn handle_failed_login(&self, user_id: &Uuid) -> Result<()> {
327        let mut users = self.users.write().await;
328
329        if let Some(user) = users.get_mut(user_id) {
330            user.failed_login_attempts += 1;
331
332            if user.failed_login_attempts >= self.config.rate_limit.lockout_threshold {
333                user.locked_until = Some(Utc::now() + Duration::from_std(self.config.rate_limit.lockout_duration).unwrap());
334                tracing::warn!(user_id = %user_id, "Account locked due to failed login attempts");
335            }
336        }
337
338        Ok(())
339    }
340
341    pub async fn verify_token(&self, token: &str) -> Result<Claims> {
342        self.jwt.verify_token(token).await
343    }
344
345    pub async fn logout(&self, session_id: &Uuid) -> Result<()> {
346        self.sessions.delete_session(session_id).await?;
347
348        self.audit.log(
349            None,
350            Some(*session_id),
351            "user.logout".to_string(),
352            "session".to_string(),
353            AuditResult::Success,
354            None,
355            None,
356            HashMap::new(),
357            0,
358        ).await;
359
360        Ok(())
361    }
362
363    // ==================== Accessors ====================
364
365    pub fn jwt_manager(&self) -> &JwtManager {
366        &self.jwt
367    }
368
369    pub fn password_manager(&self) -> &PasswordManager {
370        &self.password
371    }
372
373    pub fn oauth2_manager(&self) -> &OAuth2Manager {
374        &self.oauth2
375    }
376
377    pub fn mfa_manager(&self) -> &MfaManager {
378        &self.mfa
379    }
380
381    pub fn permission_manager(&self) -> &PermissionManager {
382        &self.permissions
383    }
384
385    pub fn session_manager(&self) -> &SessionManager {
386        &self.sessions
387    }
388
389    pub fn api_key_manager(&self) -> &ApiKeyManager {
390        &self.api_keys
391    }
392
393    pub fn risk_engine(&self) -> &RiskEngine {
394        &self.risk
395    }
396
397    pub fn audit_manager(&self) -> &AuditManager {
398        &self.audit
399    }
400
401    pub fn crypto_manager(&self) -> &CryptoManager {
402        &self.crypto
403    }
404}
405
406// Helper function para converter string para Algorithm
407fn parse_algorithm(s: &str) -> std::result::Result<jsonwebtoken::Algorithm, String> {
408    match s {
409        "HS256" => Ok(jsonwebtoken::Algorithm::HS256),
410        "HS384" => Ok(jsonwebtoken::Algorithm::HS384),
411        "HS512" => Ok(jsonwebtoken::Algorithm::HS512),
412        "RS256" => Ok(jsonwebtoken::Algorithm::RS256),
413        "RS384" => Ok(jsonwebtoken::Algorithm::RS384),
414        "RS512" => Ok(jsonwebtoken::Algorithm::RS512),
415        "ES256" => Ok(jsonwebtoken::Algorithm::ES256),
416        "ES384" => Ok(jsonwebtoken::Algorithm::ES384),
417        _ => Err(format!("Unknown algorithm: {}", s)),
418    }
419}