|
| 1 | +/* |
| 2 | + * Parseable Server (C) 2022 - 2023 Parseable, Inc. |
| 3 | + * |
| 4 | + * This program is free software: you can redistribute it and/or modify |
| 5 | + * it under the terms of the GNU Affero General Public License as |
| 6 | + * published by the Free Software Foundation, either version 3 of the |
| 7 | + * License, or (at your option) any later version. |
| 8 | + * |
| 9 | + * This program is distributed in the hope that it will be useful, |
| 10 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 | + * GNU Affero General Public License for more details. |
| 13 | + * |
| 14 | + * You should have received a copy of the GNU Affero General Public License |
| 15 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 16 | + * |
| 17 | + */ |
| 18 | + |
| 19 | +use crate::option::CONFIG; |
| 20 | +use crate::rbac::user::User; |
| 21 | +use std::collections::HashMap; |
| 22 | + |
| 23 | +use super::{ |
| 24 | + role::{Action, Permission}, |
| 25 | + user, |
| 26 | +}; |
| 27 | +use once_cell::sync::OnceCell; |
| 28 | +use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}; |
| 29 | + |
| 30 | +pub static USER_MAP: OnceCell<RwLock<UserMap>> = OnceCell::new(); |
| 31 | +pub static AUTH_MAP: OnceCell<RwLock<AuthMap>> = OnceCell::new(); |
| 32 | + |
| 33 | +pub fn user_map() -> RwLockReadGuard<'static, UserMap> { |
| 34 | + USER_MAP |
| 35 | + .get() |
| 36 | + .expect("map is set") |
| 37 | + .read() |
| 38 | + .expect("not poisoned") |
| 39 | +} |
| 40 | + |
| 41 | +pub fn mut_user_map() -> RwLockWriteGuard<'static, UserMap> { |
| 42 | + USER_MAP |
| 43 | + .get() |
| 44 | + .expect("map is set") |
| 45 | + .write() |
| 46 | + .expect("not poisoned") |
| 47 | +} |
| 48 | + |
| 49 | +pub fn auth_map() -> RwLockReadGuard<'static, AuthMap> { |
| 50 | + AUTH_MAP |
| 51 | + .get() |
| 52 | + .expect("map is set") |
| 53 | + .read() |
| 54 | + .expect("not poisoned") |
| 55 | +} |
| 56 | + |
| 57 | +pub fn mut_auth_map() -> RwLockWriteGuard<'static, AuthMap> { |
| 58 | + AUTH_MAP |
| 59 | + .get() |
| 60 | + .expect("map is set") |
| 61 | + .write() |
| 62 | + .expect("not poisoned") |
| 63 | +} |
| 64 | + |
| 65 | +// initialize the user and auth maps |
| 66 | +// the user_map is initialized from the config file and has a list of all users |
| 67 | +// the auth_map is initialized with admin user only and then gets lazily populated |
| 68 | +// as users authenticate |
| 69 | +pub fn init_auth_maps(users: Vec<User>) { |
| 70 | + let mut user_map = UserMap::from(users); |
| 71 | + let mut auth_map = AuthMap::default(); |
| 72 | + let admin = user::get_admin_user(); |
| 73 | + let admin_permissions = admin.permissions(); |
| 74 | + user_map.insert(admin); |
| 75 | + auth_map.add_user( |
| 76 | + CONFIG.parseable.username.clone(), |
| 77 | + CONFIG.parseable.password.clone(), |
| 78 | + admin_permissions, |
| 79 | + ); |
| 80 | + |
| 81 | + USER_MAP |
| 82 | + .set(RwLock::new(user_map)) |
| 83 | + .expect("map is only set once"); |
| 84 | + AUTH_MAP |
| 85 | + .set(RwLock::new(auth_map)) |
| 86 | + .expect("map is only set once"); |
| 87 | +} |
| 88 | + |
| 89 | +// AuthMap is a map of [(username, password) --> permissions] |
| 90 | +// This map is populated lazily as users send auth requests. |
| 91 | +// First auth request for a user will populate the map with |
| 92 | +// the user info (password and permissions) and subsequent |
| 93 | +// requests will check the map for the user. |
| 94 | +// If user is present in the map then we use this map for both |
| 95 | +// authentication and authorization. |
| 96 | +#[derive(Debug, Default)] |
| 97 | +pub struct AuthMap { |
| 98 | + inner: HashMap<(String, String), Vec<Permission>>, |
| 99 | +} |
| 100 | + |
| 101 | +impl AuthMap { |
| 102 | + pub fn add_user(&mut self, username: String, password: String, permissions: Vec<Permission>) { |
| 103 | + self.inner.insert((username, password), permissions); |
| 104 | + } |
| 105 | + |
| 106 | + pub fn remove(&mut self, username: &str) { |
| 107 | + self.inner.retain(|(x, _), _| x != username) |
| 108 | + } |
| 109 | + |
| 110 | + // returns None if user is not in the map |
| 111 | + // Otherwise returns Some(is_authenticated) |
| 112 | + pub fn check_auth( |
| 113 | + &self, |
| 114 | + key: &(String, String), |
| 115 | + required_action: Action, |
| 116 | + on_stream: Option<&str>, |
| 117 | + ) -> Option<bool> { |
| 118 | + self.inner.get(key).map(|perms| { |
| 119 | + perms.iter().any(|user_perm| { |
| 120 | + match *user_perm { |
| 121 | + // if any action is ALL then we we authorize |
| 122 | + Permission::Unit(action) => action == required_action || action == Action::All, |
| 123 | + Permission::Stream(action, ref stream) => { |
| 124 | + let ok_stream = if let Some(on_stream) = on_stream { |
| 125 | + stream == on_stream || stream == "*" |
| 126 | + } else { |
| 127 | + // if no stream to match then stream check is not needed |
| 128 | + true |
| 129 | + }; |
| 130 | + (action == required_action || action == Action::All) && ok_stream |
| 131 | + } |
| 132 | + } |
| 133 | + }) |
| 134 | + }) |
| 135 | + } |
| 136 | +} |
| 137 | + |
| 138 | +// UserMap is a map of [username --> User] |
| 139 | +// This map is populated at startup with the list of users from parseable.json file |
| 140 | +#[derive(Debug, Default, Clone, derive_more::Deref, derive_more::DerefMut)] |
| 141 | +pub struct UserMap(HashMap<String, User>); |
| 142 | + |
| 143 | +impl UserMap { |
| 144 | + pub fn insert(&mut self, user: User) { |
| 145 | + self.0.insert(user.username.clone(), user); |
| 146 | + } |
| 147 | +} |
| 148 | + |
| 149 | +impl From<Vec<User>> for UserMap { |
| 150 | + fn from(users: Vec<User>) -> Self { |
| 151 | + let mut map = Self::default(); |
| 152 | + map.extend(users.into_iter().map(|user| (user.username.clone(), user))); |
| 153 | + map |
| 154 | + } |
| 155 | +} |
0 commit comments