Skip to main content

paas_server/auth/
token.rs

1use crate::auth::core::{AuthInfo, TokenValidator};
2use actix_web::error::ErrorUnauthorized;
3use actix_web::Error;
4use serde::{Deserialize, Serialize};
5use std::collections::{HashMap, HashSet};
6use std::future::Future;
7use std::pin::Pin;
8use std::sync::Arc;
9
10pub struct SimpleTokenAuthConfig {
11    pub token_users_path: String,
12}
13
14#[derive(Clone, Serialize, Deserialize, Debug, Eq, PartialEq)]
15pub struct User {
16    pub username: String,
17    pub groups: Vec<String>,
18    pub tokens: HashSet<String>,
19}
20
21impl User {
22    pub fn new(username: &str, groups: Vec<&str>, tokens: Vec<&str>) -> User {
23        User {
24            username: username.to_string(),
25            groups: groups.into_iter().map(|s| s.to_string()).collect(),
26            tokens: tokens.into_iter().map(|s| s.to_string()).collect(),
27        }
28    }
29}
30
31#[derive(Clone, Debug)]
32pub struct SimpleTokenValidator {
33    users: Arc<HashMap<String, User>>,
34    token_to_user: Arc<HashMap<String, String>>, // token -> username mapping for quick lookup
35}
36
37impl SimpleTokenValidator {
38    pub fn load(file_path: &str) -> Self {
39        let file = std::fs::read_to_string(file_path).expect("Failed to read access rules file");
40        let users = serde_yml::from_str(&file).expect("Failed to parse access rules file");
41        Self::new(users)
42    }
43    pub fn new(users: Vec<User>) -> Self {
44        let mut user_map = HashMap::new();
45        let mut token_map = HashMap::new();
46
47        for user in users {
48            let username = user.username.clone();
49
50            for token in &user.tokens {
51                token_map.insert(token.clone(), username.clone());
52            }
53
54            user_map.insert(username, user);
55        }
56
57        Self {
58            users: Arc::new(user_map),
59            token_to_user: Arc::new(token_map),
60        }
61    }
62}
63
64impl TokenValidator for SimpleTokenValidator {
65    fn validate_token<'a>(
66        &'a self,
67        token: &'a str,
68    ) -> Pin<Box<dyn Future<Output = Result<AuthInfo, Error>> + Send + 'a>> {
69        let token = token.to_string();
70        let token_to_user = self.token_to_user.clone();
71        let users = self.users.clone();
72
73        Box::pin(async move {
74            // Check if token exists in token map
75            if let Some(username) = token_to_user.get(&token) {
76                // Verify user exists
77                if let Some(user) = users.get(username) {
78                    // Return user information
79                    Ok(AuthInfo {
80                        name: user.username.clone(),
81                        sub: user.username.clone(),
82                        groups: user.groups.clone(),
83                    })
84                } else {
85                    // Token mapped to non-existent user
86                    Err(ErrorUnauthorized("Invalid user"))
87                }
88            } else {
89                // Token not found
90                Err(ErrorUnauthorized("Invalid token"))
91            }
92        })
93    }
94}