1use crate::multi_tenancy::types::{MultiTenancyError, MultiTenancyResult};
4use serde::{Deserialize, Serialize};
5use std::collections::{HashMap, HashSet};
6use std::sync::{Arc, RwLock};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub enum Permission {
11 Read,
13 Write,
15 Delete,
17 BuildIndex,
19 Admin,
21 ViewMetrics,
23 ManageBilling,
25 Custom(u32),
27}
28
29impl Permission {
30 pub fn includes(&self, other: &Permission) -> bool {
32 match self {
33 Self::Admin => true, _ => self == other,
35 }
36 }
37
38 pub fn name(&self) -> &'static str {
40 match self {
41 Self::Read => "read",
42 Self::Write => "write",
43 Self::Delete => "delete",
44 Self::BuildIndex => "build_index",
45 Self::Admin => "admin",
46 Self::ViewMetrics => "view_metrics",
47 Self::ManageBilling => "manage_billing",
48 Self::Custom(_) => "custom",
49 }
50 }
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct Role {
56 pub name: String,
58 pub permissions: HashSet<Permission>,
60 pub description: Option<String>,
62}
63
64impl Role {
65 pub fn new(name: impl Into<String>) -> Self {
67 Self {
68 name: name.into(),
69 permissions: HashSet::new(),
70 description: None,
71 }
72 }
73
74 pub fn readonly() -> Self {
76 let mut role = Self::new("readonly");
77 role.permissions.insert(Permission::Read);
78 role.permissions.insert(Permission::ViewMetrics);
79 role.description = Some("Read-only access to vectors and metrics".to_string());
80 role
81 }
82
83 pub fn readwrite() -> Self {
85 let mut role = Self::new("readwrite");
86 role.permissions.insert(Permission::Read);
87 role.permissions.insert(Permission::Write);
88 role.permissions.insert(Permission::ViewMetrics);
89 role.description = Some("Read and write access to vectors".to_string());
90 role
91 }
92
93 pub fn admin() -> Self {
95 let mut role = Self::new("admin");
96 role.permissions.insert(Permission::Admin);
97 role.description = Some("Full administrative access".to_string());
98 role
99 }
100
101 pub fn add_permission(&mut self, permission: Permission) {
103 self.permissions.insert(permission);
104 }
105
106 pub fn has_permission(&self, permission: Permission) -> bool {
108 self.permissions.iter().any(|p| p.includes(&permission))
109 }
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct AccessPolicy {
115 pub tenant_id: String,
117 pub user_roles: HashMap<String, Vec<String>>,
119 pub roles: HashMap<String, Role>,
121 pub ip_whitelist: Vec<String>,
123 pub ip_blacklist: Vec<String>,
125}
126
127impl AccessPolicy {
128 pub fn new(tenant_id: impl Into<String>) -> Self {
130 let mut policy = Self {
131 tenant_id: tenant_id.into(),
132 user_roles: HashMap::new(),
133 roles: HashMap::new(),
134 ip_whitelist: Vec::new(),
135 ip_blacklist: Vec::new(),
136 };
137
138 policy.add_role(Role::readonly());
140 policy.add_role(Role::readwrite());
141 policy.add_role(Role::admin());
142
143 policy
144 }
145
146 pub fn add_role(&mut self, role: Role) {
148 self.roles.insert(role.name.clone(), role);
149 }
150
151 pub fn assign_role(&mut self, user_id: impl Into<String>, role_name: impl Into<String>) {
153 self.user_roles
154 .entry(user_id.into())
155 .or_default()
156 .push(role_name.into());
157 }
158
159 pub fn has_permission(&self, user_id: &str, permission: Permission) -> bool {
161 if let Some(role_names) = self.user_roles.get(user_id) {
162 for role_name in role_names {
163 if let Some(role) = self.roles.get(role_name) {
164 if role.has_permission(permission) {
165 return true;
166 }
167 }
168 }
169 }
170 false
171 }
172
173 pub fn is_ip_allowed(&self, ip: &str) -> bool {
175 if self.ip_blacklist.contains(&ip.to_string()) {
177 return false;
178 }
179
180 if self.ip_whitelist.is_empty() {
182 return true;
183 }
184
185 self.ip_whitelist.contains(&ip.to_string())
187 }
188}
189
190pub struct AccessControl {
192 policies: Arc<RwLock<HashMap<String, AccessPolicy>>>,
194}
195
196impl AccessControl {
197 pub fn new() -> Self {
199 Self {
200 policies: Arc::new(RwLock::new(HashMap::new())),
201 }
202 }
203
204 pub fn set_policy(&self, policy: AccessPolicy) -> MultiTenancyResult<()> {
206 self.policies
207 .write()
208 .map_err(|e| MultiTenancyError::InternalError {
209 message: format!("Lock error: {}", e),
210 })?
211 .insert(policy.tenant_id.clone(), policy);
212 Ok(())
213 }
214
215 pub fn get_policy(&self, tenant_id: &str) -> MultiTenancyResult<AccessPolicy> {
217 self.policies
218 .read()
219 .map_err(|e| MultiTenancyError::InternalError {
220 message: format!("Lock error: {}", e),
221 })?
222 .get(tenant_id)
223 .cloned()
224 .ok_or_else(|| MultiTenancyError::TenantNotFound {
225 tenant_id: tenant_id.to_string(),
226 })
227 }
228
229 pub fn check_permission(
231 &self,
232 tenant_id: &str,
233 user_id: &str,
234 permission: Permission,
235 ) -> MultiTenancyResult<bool> {
236 let policy = self.get_policy(tenant_id)?;
237 Ok(policy.has_permission(user_id, permission))
238 }
239
240 pub fn authorize(
242 &self,
243 tenant_id: &str,
244 user_id: &str,
245 permission: Permission,
246 client_ip: Option<&str>,
247 ) -> MultiTenancyResult<()> {
248 let policy = self.get_policy(tenant_id)?;
249
250 if let Some(ip) = client_ip {
252 if !policy.is_ip_allowed(ip) {
253 return Err(MultiTenancyError::AccessDenied {
254 tenant_id: tenant_id.to_string(),
255 reason: format!("IP {} not allowed", ip),
256 });
257 }
258 }
259
260 if !policy.has_permission(user_id, permission) {
262 return Err(MultiTenancyError::AccessDenied {
263 tenant_id: tenant_id.to_string(),
264 reason: format!("User {} lacks permission {:?}", user_id, permission),
265 });
266 }
267
268 Ok(())
269 }
270
271 pub fn create_default_policy(&self, tenant_id: impl Into<String>) -> MultiTenancyResult<()> {
273 let policy = AccessPolicy::new(tenant_id);
274 self.set_policy(policy)
275 }
276}
277
278impl Default for AccessControl {
279 fn default() -> Self {
280 Self::new()
281 }
282}
283
284#[cfg(test)]
285mod tests {
286 use super::*;
287
288 #[test]
289 fn test_permissions() {
290 assert!(Permission::Admin.includes(&Permission::Read));
291 assert!(Permission::Admin.includes(&Permission::Write));
292 assert!(!Permission::Read.includes(&Permission::Write));
293 assert!(Permission::Read.includes(&Permission::Read));
294 }
295
296 #[test]
297 fn test_role_creation() {
298 let role = Role::readonly();
299 assert!(role.has_permission(Permission::Read));
300 assert!(!role.has_permission(Permission::Write));
301 assert!(!role.has_permission(Permission::Delete));
302
303 let role = Role::readwrite();
304 assert!(role.has_permission(Permission::Read));
305 assert!(role.has_permission(Permission::Write));
306 assert!(!role.has_permission(Permission::Delete));
307
308 let role = Role::admin();
309 assert!(role.has_permission(Permission::Read));
310 assert!(role.has_permission(Permission::Write));
311 assert!(role.has_permission(Permission::Delete));
312 assert!(role.has_permission(Permission::Admin));
313 }
314
315 #[test]
316 fn test_access_policy() {
317 let mut policy = AccessPolicy::new("tenant1");
318
319 policy.assign_role("user1", "readonly");
321 policy.assign_role("user2", "readwrite");
322 policy.assign_role("user3", "admin");
323
324 assert!(policy.has_permission("user1", Permission::Read));
326 assert!(!policy.has_permission("user1", Permission::Write));
327
328 assert!(policy.has_permission("user2", Permission::Read));
329 assert!(policy.has_permission("user2", Permission::Write));
330 assert!(!policy.has_permission("user2", Permission::Delete));
331
332 assert!(policy.has_permission("user3", Permission::Read));
333 assert!(policy.has_permission("user3", Permission::Write));
334 assert!(policy.has_permission("user3", Permission::Delete));
335 assert!(policy.has_permission("user3", Permission::Admin));
336 }
337
338 #[test]
339 fn test_ip_restrictions() {
340 let mut policy = AccessPolicy::new("tenant1");
341
342 assert!(policy.is_ip_allowed("192.168.1.1"));
344 assert!(policy.is_ip_allowed("10.0.0.1"));
345
346 policy.ip_blacklist.push("192.168.1.100".to_string());
348 assert!(!policy.is_ip_allowed("192.168.1.100"));
349 assert!(policy.is_ip_allowed("192.168.1.1"));
350
351 policy.ip_whitelist.push("192.168.1.1".to_string());
353 policy.ip_whitelist.push("192.168.1.2".to_string());
354 assert!(policy.is_ip_allowed("192.168.1.1"));
355 assert!(policy.is_ip_allowed("192.168.1.2"));
356 assert!(!policy.is_ip_allowed("10.0.0.1"));
357 assert!(!policy.is_ip_allowed("192.168.1.100")); }
359
360 #[test]
361 fn test_access_control_manager() {
362 let ac = AccessControl::new();
363
364 ac.create_default_policy("tenant1").unwrap();
366
367 let mut policy = ac.get_policy("tenant1").unwrap();
369 policy.assign_role("user1", "readonly");
370 policy.assign_role("user2", "admin");
371 ac.set_policy(policy).unwrap();
372
373 assert!(ac
375 .check_permission("tenant1", "user1", Permission::Read)
376 .unwrap());
377 assert!(!ac
378 .check_permission("tenant1", "user1", Permission::Write)
379 .unwrap());
380
381 assert!(ac
382 .check_permission("tenant1", "user2", Permission::Admin)
383 .unwrap());
384
385 assert!(ac
387 .authorize("tenant1", "user1", Permission::Read, None)
388 .is_ok());
389 assert!(ac
390 .authorize("tenant1", "user1", Permission::Write, None)
391 .is_err());
392 assert!(ac
393 .authorize("tenant1", "user2", Permission::Write, None)
394 .is_ok());
395 }
396
397 #[test]
398 fn test_authorize_with_ip() {
399 let ac = AccessControl::new();
400 let mut policy = AccessPolicy::new("tenant1");
401 policy.assign_role("user1", "readonly");
402 policy.ip_whitelist.push("192.168.1.1".to_string());
403 ac.set_policy(policy).unwrap();
404
405 assert!(ac
407 .authorize("tenant1", "user1", Permission::Read, Some("192.168.1.1"))
408 .is_ok());
409
410 assert!(ac
412 .authorize("tenant1", "user1", Permission::Read, Some("10.0.0.1"))
413 .is_err());
414 }
415
416 #[test]
417 fn test_custom_roles() {
418 let mut role = Role::new("custom");
419 role.add_permission(Permission::Read);
420 role.add_permission(Permission::ViewMetrics);
421 role.add_permission(Permission::Custom(100));
422
423 assert!(role.has_permission(Permission::Read));
424 assert!(role.has_permission(Permission::ViewMetrics));
425 assert!(role.has_permission(Permission::Custom(100)));
426 assert!(!role.has_permission(Permission::Write));
427 }
428}