1use crate::auth::{ApiKey, AuthError, AuthState, Permission, Role, User};
6use crate::gateway::GatewayState;
7use axum::{extract::State, http::StatusCode, response::IntoResponse, Json};
8use serde::{Deserialize, Serialize};
9use std::collections::HashSet;
10use uuid::Uuid;
11
12#[derive(Debug, Deserialize)]
18pub struct LoginRequest {
19 pub username: String,
20 pub password: String,
21}
22
23#[derive(Debug, Serialize)]
25pub struct LoginResponse {
26 pub token: String,
27 pub expires_in: u64,
28 pub user: UserInfo,
29}
30
31#[derive(Debug, Deserialize)]
33pub struct RegisterRequest {
34 pub username: String,
35 pub password: String,
36 pub role: Option<Role>,
37}
38
39#[derive(Debug, Serialize)]
41pub struct RegisterResponse {
42 pub success: bool,
43 pub user: UserInfo,
44}
45
46#[derive(Debug, Serialize)]
48pub struct UserInfo {
49 pub id: String,
50 pub username: String,
51 pub role: Role,
52 pub permissions: Vec<Permission>,
53 pub active: bool,
54 pub created_at: u64,
55}
56
57impl From<&User> for UserInfo {
58 fn from(user: &User) -> Self {
59 Self {
60 id: user.id.to_string(),
61 username: user.username.clone(),
62 role: user.role,
63 permissions: user.permissions().into_iter().collect(),
64 active: user.active,
65 created_at: user.created_at,
66 }
67 }
68}
69
70#[derive(Debug, Serialize)]
72pub struct RefreshResponse {
73 pub token: String,
74 pub expires_in: u64,
75}
76
77#[derive(Debug, Deserialize)]
79pub struct UpdatePermissionsRequest {
80 pub username: String,
81 pub permissions: HashSet<Permission>,
82}
83
84#[derive(Debug, Serialize)]
86pub struct SuccessResponse {
87 pub success: bool,
88 pub message: String,
89}
90
91fn get_auth_state(state: &GatewayState) -> Result<&AuthState, AuthHandlerError> {
97 state.auth.as_ref().ok_or_else(|| {
98 AuthHandlerError::from(AuthError::InvalidToken(
99 "Authentication not enabled".to_string(),
100 ))
101 })
102}
103
104pub async fn login_handler(
114 State(gateway_state): State<GatewayState>,
115 Json(req): Json<LoginRequest>,
116) -> Result<Json<LoginResponse>, AuthHandlerError> {
117 let auth_state = get_auth_state(&gateway_state)?;
118
119 let user = auth_state
121 .user_store
122 .authenticate(&req.username, &req.password)?;
123
124 let token = auth_state.jwt_manager.generate_token(&user, 24)?;
126
127 Ok(Json(LoginResponse {
128 token,
129 expires_in: 24 * 3600, user: UserInfo::from(&user),
131 }))
132}
133
134pub async fn register_handler(
140 State(gateway_state): State<GatewayState>,
141 Json(req): Json<RegisterRequest>,
142) -> Result<Json<RegisterResponse>, AuthHandlerError> {
143 let auth_state = get_auth_state(&gateway_state)?;
144
145 let role = req.role.unwrap_or(Role::User);
148
149 let user = User::new(req.username, &req.password, role)?;
151
152 auth_state.user_store.add_user(user.clone())?;
154
155 Ok(Json(RegisterResponse {
156 success: true,
157 user: UserInfo::from(&user),
158 }))
159}
160
161pub async fn me_handler(
167 State(gateway_state): State<GatewayState>,
168 headers: axum::http::HeaderMap,
169) -> Result<Json<UserInfo>, AuthHandlerError> {
170 let auth_state = get_auth_state(&gateway_state)?;
171
172 let token = extract_token_from_headers(&headers)?;
174 let claims = auth_state.jwt_manager.validate_token(token)?;
175
176 let user = auth_state.user_store.get_user(&claims.username)?;
177
178 Ok(Json(UserInfo::from(&user)))
179}
180
181fn extract_token_from_headers(headers: &axum::http::HeaderMap) -> Result<&str, AuthError> {
183 let auth_header = headers
184 .get(axum::http::header::AUTHORIZATION)
185 .and_then(|h| h.to_str().ok())
186 .ok_or(AuthError::InvalidToken(
187 "Missing Authorization header".to_string(),
188 ))?;
189
190 auth_header
191 .strip_prefix("Bearer ")
192 .ok_or_else(|| AuthError::InvalidToken("Invalid Authorization format".to_string()))
193}
194
195pub async fn update_permissions_handler(
201 State(gateway_state): State<GatewayState>,
202 headers: axum::http::HeaderMap,
203 Json(req): Json<UpdatePermissionsRequest>,
204) -> Result<Json<SuccessResponse>, AuthHandlerError> {
205 let auth_state = get_auth_state(&gateway_state)?;
206
207 let token = extract_token_from_headers(&headers)?;
209 let claims = auth_state.jwt_manager.validate_token(token)?;
210
211 let requester = auth_state.user_store.get_user(&claims.username)?;
213
214 if !requester.has_permission(Permission::SystemAdmin) {
215 return Err(AuthHandlerError::from(AuthError::InsufficientPermissions));
216 }
217
218 auth_state
220 .user_store
221 .update_permissions(&req.username, req.permissions)?;
222
223 Ok(Json(SuccessResponse {
224 success: true,
225 message: format!("Permissions updated for user: {}", req.username),
226 }))
227}
228
229pub async fn deactivate_user_handler(
235 State(gateway_state): State<GatewayState>,
236 headers: axum::http::HeaderMap,
237 axum::extract::Path(username): axum::extract::Path<String>,
238) -> Result<Json<SuccessResponse>, AuthHandlerError> {
239 let auth_state = get_auth_state(&gateway_state)?;
240
241 let token = extract_token_from_headers(&headers)?;
243 let claims = auth_state.jwt_manager.validate_token(token)?;
244
245 let requester = auth_state.user_store.get_user(&claims.username)?;
247
248 if !requester.has_permission(Permission::SystemAdmin) {
249 return Err(AuthHandlerError::from(AuthError::InsufficientPermissions));
250 }
251
252 auth_state.user_store.deactivate_user(&username)?;
254
255 Ok(Json(SuccessResponse {
256 success: true,
257 message: format!("User deactivated: {}", username),
258 }))
259}
260
261#[derive(Debug, Deserialize)]
267pub struct CreateApiKeyRequest {
268 pub name: String,
269}
270
271#[derive(Debug, Serialize)]
273pub struct CreateApiKeyResponse {
274 pub key: String,
275 pub key_info: ApiKeyInfo,
276}
277
278#[derive(Debug, Serialize)]
280pub struct ApiKeyInfo {
281 pub id: String,
282 pub prefix: String,
283 pub name: String,
284 pub created_at: u64,
285 pub last_used_at: Option<u64>,
286 pub active: bool,
287}
288
289impl From<&ApiKey> for ApiKeyInfo {
290 fn from(key: &ApiKey) -> Self {
291 Self {
292 id: key.id.to_string(),
293 prefix: key.prefix.clone(),
294 name: key.name.clone(),
295 created_at: key.created_at,
296 last_used_at: key.last_used_at,
297 active: key.active,
298 }
299 }
300}
301
302pub async fn create_api_key_handler(
306 State(gateway_state): State<GatewayState>,
307 headers: axum::http::HeaderMap,
308 Json(req): Json<CreateApiKeyRequest>,
309) -> Result<Json<CreateApiKeyResponse>, AuthHandlerError> {
310 let auth_state = get_auth_state(&gateway_state)?;
311
312 let token = extract_token_from_headers(&headers)?;
314 let claims = auth_state.jwt_manager.validate_token(token)?;
315
316 let user = auth_state.user_store.get_user(&claims.username)?;
318
319 let (api_key, raw_key) = ApiKey::new(user.id, req.name)?;
321
322 auth_state.api_key_store.add_key(api_key.clone())?;
324
325 Ok(Json(CreateApiKeyResponse {
326 key: raw_key,
327 key_info: ApiKeyInfo::from(&api_key),
328 }))
329}
330
331pub async fn list_api_keys_handler(
335 State(gateway_state): State<GatewayState>,
336 headers: axum::http::HeaderMap,
337) -> Result<Json<Vec<ApiKeyInfo>>, AuthHandlerError> {
338 let auth_state = get_auth_state(&gateway_state)?;
339
340 let token = extract_token_from_headers(&headers)?;
342 let claims = auth_state.jwt_manager.validate_token(token)?;
343
344 let user = auth_state.user_store.get_user(&claims.username)?;
346
347 let keys = auth_state.api_key_store.list_user_keys(&user.id);
349 let key_infos: Vec<ApiKeyInfo> = keys.iter().map(ApiKeyInfo::from).collect();
350
351 Ok(Json(key_infos))
352}
353
354pub async fn revoke_api_key_handler(
358 State(gateway_state): State<GatewayState>,
359 headers: axum::http::HeaderMap,
360 axum::extract::Path(key_id_str): axum::extract::Path<String>,
361) -> Result<Json<SuccessResponse>, AuthHandlerError> {
362 let auth_state = get_auth_state(&gateway_state)?;
363
364 let token = extract_token_from_headers(&headers)?;
366 let claims = auth_state.jwt_manager.validate_token(token)?;
367
368 let user = auth_state.user_store.get_user(&claims.username)?;
370
371 let key_id = Uuid::parse_str(&key_id_str)
373 .map_err(|_| AuthHandlerError::from(AuthError::InvalidCredentials))?;
374
375 let key = auth_state.api_key_store.get_key(&key_id)?;
377 if key.user_id != user.id && !user.has_permission(Permission::SystemAdmin) {
378 return Err(AuthHandlerError::from(AuthError::InsufficientPermissions));
379 }
380
381 auth_state.api_key_store.revoke_key(&key_id)?;
383
384 Ok(Json(SuccessResponse {
385 success: true,
386 message: format!("API key revoked: {}", key_id),
387 }))
388}
389
390pub async fn delete_api_key_handler(
394 State(gateway_state): State<GatewayState>,
395 headers: axum::http::HeaderMap,
396 axum::extract::Path(key_id_str): axum::extract::Path<String>,
397) -> Result<Json<SuccessResponse>, AuthHandlerError> {
398 let auth_state = get_auth_state(&gateway_state)?;
399
400 let token = extract_token_from_headers(&headers)?;
402 let claims = auth_state.jwt_manager.validate_token(token)?;
403
404 let user = auth_state.user_store.get_user(&claims.username)?;
406
407 let key_id = Uuid::parse_str(&key_id_str)
409 .map_err(|_| AuthHandlerError::from(AuthError::InvalidCredentials))?;
410
411 let key = auth_state.api_key_store.get_key(&key_id)?;
413 if key.user_id != user.id && !user.has_permission(Permission::SystemAdmin) {
414 return Err(AuthHandlerError::from(AuthError::InsufficientPermissions));
415 }
416
417 auth_state.api_key_store.delete_key(&key_id)?;
419
420 Ok(Json(SuccessResponse {
421 success: true,
422 message: format!("API key deleted: {}", key_id),
423 }))
424}
425
426#[derive(Debug)]
432pub struct AuthHandlerError {
433 error: AuthError,
434}
435
436impl From<AuthError> for AuthHandlerError {
437 fn from(error: AuthError) -> Self {
438 Self { error }
439 }
440}
441
442impl IntoResponse for AuthHandlerError {
443 fn into_response(self) -> axum::response::Response {
444 let (status, message) = match self.error {
445 AuthError::InvalidCredentials => {
446 (StatusCode::UNAUTHORIZED, "Invalid credentials".to_string())
447 }
448 AuthError::InvalidToken(msg) => (StatusCode::UNAUTHORIZED, msg),
449 AuthError::TokenExpired => (StatusCode::UNAUTHORIZED, "Token expired".to_string()),
450 AuthError::InsufficientPermissions => (
451 StatusCode::FORBIDDEN,
452 "Insufficient permissions".to_string(),
453 ),
454 AuthError::UserNotFound => (StatusCode::NOT_FOUND, "User not found".to_string()),
455 AuthError::HashError(msg) => (StatusCode::INTERNAL_SERVER_ERROR, msg),
456 AuthError::JwtError(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()),
457 };
458
459 (status, message).into_response()
460 }
461}