dx_forge/server/
authentication.rs

1use anyhow::{anyhow, Result};
2use serde::{Deserialize, Serialize};
3use sha2::{Digest, Sha256};
4use std::collections::HashMap;
5use std::sync::Arc;
6use parking_lot::RwLock;
7use uuid::Uuid;
8use chrono::{DateTime, Duration, Utc};
9
10/// User role for access control
11#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(rename_all = "lowercase")]
13pub enum Role {
14    Admin,
15    Developer,
16    Viewer,
17}
18
19/// User account information
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct User {
22    pub id: String,
23    pub username: String,
24    #[serde(skip_serializing)]
25    pub password_hash: String,
26    pub email: Option<String>,
27    pub role: Role,
28    pub created_at: DateTime<Utc>,
29    pub last_login: Option<DateTime<Utc>>,
30}
31
32impl User {
33    /// Create a new user with hashed password
34    pub fn new(username: String, password: &str, role: Role) -> Self {
35        Self {
36            id: Uuid::new_v4().to_string(),
37            username,
38            password_hash: hash_password(password),
39            email: None,
40            role,
41            created_at: Utc::now(),
42            last_login: None,
43        }
44    }
45
46    /// Verify password
47    pub fn verify_password(&self, password: &str) -> bool {
48        self.password_hash == hash_password(password)
49    }
50
51    /// Check if user has permission
52    pub fn has_permission(&self, required_role: &Role) -> bool {
53        match (&self.role, required_role) {
54            (Role::Admin, _) => true,
55            (Role::Developer, Role::Developer | Role::Viewer) => true,
56            (Role::Viewer, Role::Viewer) => true,
57            _ => false,
58        }
59    }
60}
61
62/// Session token
63#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct Session {
65    pub token: String,
66    pub user_id: String,
67    pub username: String,
68    pub role: Role,
69    pub created_at: DateTime<Utc>,
70    pub expires_at: DateTime<Utc>,
71}
72
73impl Session {
74    /// Create a new session
75    pub fn new(user: &User, duration_hours: i64) -> Self {
76        let now = Utc::now();
77        Self {
78            token: Uuid::new_v4().to_string(),
79            user_id: user.id.clone(),
80            username: user.username.clone(),
81            role: user.role.clone(),
82            created_at: now,
83            expires_at: now + Duration::hours(duration_hours),
84        }
85    }
86
87    /// Check if session is expired
88    pub fn is_expired(&self) -> bool {
89        Utc::now() > self.expires_at
90    }
91}
92
93/// Authentication manager
94pub struct AuthManager {
95    users: Arc<RwLock<HashMap<String, User>>>,
96    sessions: Arc<RwLock<HashMap<String, Session>>>,
97}
98
99impl AuthManager {
100    /// Create a new authentication manager
101    pub fn new() -> Self {
102        let mut users = HashMap::new();
103        
104        // Create default admin user
105        let admin = User::new("admin".to_string(), "admin123", Role::Admin);
106        users.insert(admin.username.clone(), admin);
107
108        Self {
109            users: Arc::new(RwLock::new(users)),
110            sessions: Arc::new(RwLock::new(HashMap::new())),
111        }
112    }
113
114    /// Register a new user
115    pub fn register(&self, username: String, password: &str, role: Role) -> Result<User> {
116        let mut users = self.users.write();
117        
118        if users.contains_key(&username) {
119            return Err(anyhow!("Username already exists"));
120        }
121
122        let user = User::new(username.clone(), password, role);
123        users.insert(username, user.clone());
124        
125        Ok(user)
126    }
127
128    /// Authenticate user and create session
129    pub fn login(&self, username: &str, password: &str) -> Result<Session> {
130        let mut users = self.users.write();
131        
132        let user = users
133            .get_mut(username)
134            .ok_or_else(|| anyhow!("Invalid username or password"))?;
135
136        if !user.verify_password(password) {
137            return Err(anyhow!("Invalid username or password"));
138        }
139
140        // Update last login
141        user.last_login = Some(Utc::now());
142
143        // Create session (24 hour duration)
144        let session = Session::new(user, 24);
145        
146        let mut sessions = self.sessions.write();
147        sessions.insert(session.token.clone(), session.clone());
148
149        Ok(session)
150    }
151
152    /// Validate session token
153    pub fn validate_token(&self, token: &str) -> Result<Session> {
154        let mut sessions = self.sessions.write();
155        
156        let session = sessions
157            .get(token)
158            .ok_or_else(|| anyhow!("Invalid or expired session"))?;
159
160        if session.is_expired() {
161            sessions.remove(token);
162            return Err(anyhow!("Session expired"));
163        }
164
165        Ok(session.clone())
166    }
167
168    /// Logout and invalidate session
169    pub fn logout(&self, token: &str) -> Result<()> {
170        let mut sessions = self.sessions.write();
171        sessions.remove(token);
172        Ok(())
173    }
174
175    /// Get user by username
176    pub fn get_user(&self, username: &str) -> Option<User> {
177        let users = self.users.read();
178        users.get(username).cloned()
179    }
180
181    /// List all users
182    pub fn list_users(&self) -> Vec<User> {
183        let users = self.users.read();
184        users.values().cloned().collect()
185    }
186
187    /// Update user password
188    pub fn update_password(&self, username: &str, old_password: &str, new_password: &str) -> Result<()> {
189        let mut users = self.users.write();
190        
191        let user = users
192            .get_mut(username)
193            .ok_or_else(|| anyhow!("User not found"))?;
194
195        if !user.verify_password(old_password) {
196            return Err(anyhow!("Invalid current password"));
197        }
198
199        user.password_hash = hash_password(new_password);
200        Ok(())
201    }
202
203    /// Delete user
204    pub fn delete_user(&self, username: &str) -> Result<()> {
205        let mut users = self.users.write();
206        users.remove(username).ok_or_else(|| anyhow!("User not found"))?;
207        Ok(())
208    }
209
210    /// Clean expired sessions
211    pub fn clean_expired_sessions(&self) {
212        let mut sessions = self.sessions.write();
213        sessions.retain(|_, session| !session.is_expired());
214    }
215}
216
217impl Default for AuthManager {
218    fn default() -> Self {
219        Self::new()
220    }
221}
222
223/// Hash password using SHA-256
224fn hash_password(password: &str) -> String {
225    let mut hasher = Sha256::new();
226    hasher.update(password.as_bytes());
227    format!("{:x}", hasher.finalize())
228}
229
230/// Login request
231#[derive(Debug, Deserialize)]
232pub struct LoginRequest {
233    pub username: String,
234    pub password: String,
235}
236
237/// Login response
238#[derive(Debug, Serialize)]
239pub struct LoginResponse {
240    pub token: String,
241    pub username: String,
242    pub role: Role,
243    pub expires_at: DateTime<Utc>,
244}
245
246/// User creation request
247#[derive(Debug, Deserialize)]
248pub struct CreateUserRequest {
249    pub username: String,
250    pub password: String,
251    pub role: Role,
252    pub email: Option<String>,
253}
254
255/// Password change request
256#[derive(Debug, Deserialize)]
257pub struct ChangePasswordRequest {
258    pub old_password: String,
259    pub new_password: String,
260}