Skip to main content

litellm_rs/auth/
password.rs

1//! Password management operations
2
3use super::system::AuthSystem;
4use crate::utils::auth::crypto::keys::generate_token;
5use crate::utils::auth::crypto::password::{hash_password, verify_password};
6use crate::utils::error::gateway_error::{GatewayError, Result};
7use tracing::info;
8use uuid::Uuid;
9
10impl AuthSystem {
11    /// Change user password
12    pub async fn change_password(
13        &self,
14        user_id: Uuid,
15        old_password: &str,
16        new_password: &str,
17    ) -> Result<()> {
18        info!("Changing password for user: {}", user_id);
19
20        // Get user
21        let user = self
22            .storage
23            .db()
24            .find_user_by_id(user_id)
25            .await?
26            .ok_or_else(|| GatewayError::not_found("User not found"))?;
27
28        // Verify old password
29        if !verify_password(old_password, &user.password_hash)? {
30            return Err(GatewayError::auth("Invalid current password"));
31        }
32
33        // Hash new password
34        let new_password_hash = hash_password(new_password)?;
35
36        // Update password
37        self.storage
38            .db()
39            .update_user_password(user_id, &new_password_hash)
40            .await?;
41
42        info!("Password changed successfully for user: {}", user_id);
43        Ok(())
44    }
45
46    /// Reset password (generate reset token)
47    pub async fn request_password_reset(&self, email: &str) -> Result<String> {
48        info!("Password reset requested for email: {}", email);
49
50        // Find user by email
51        let user = self
52            .storage
53            .db()
54            .find_user_by_email(email)
55            .await?
56            .ok_or_else(|| GatewayError::not_found("User not found"))?;
57
58        // Generate reset token
59        let reset_token = generate_token(32);
60        let expires_at = chrono::Utc::now() + chrono::Duration::hours(1);
61
62        // Store reset token
63        self.storage
64            .db()
65            .store_password_reset_token(user.id(), &reset_token, expires_at)
66            .await?;
67
68        info!("Password reset token generated for user: {}", user.id());
69        Ok(reset_token)
70    }
71
72    /// Reset password using token
73    pub async fn reset_password(&self, token: &str, new_password: &str) -> Result<()> {
74        info!("Resetting password with token");
75
76        // Hash new password
77        let password_hash = hash_password(new_password)?;
78
79        // Atomically verify token, update password, and invalidate token
80        // in a single transaction to prevent TOCTOU race conditions
81        let success = self
82            .storage
83            .db()
84            .reset_password_with_token(token, &password_hash)
85            .await?;
86
87        if !success {
88            return Err(GatewayError::auth("Invalid or expired reset token"));
89        }
90
91        info!("Password reset successfully");
92        Ok(())
93    }
94}