1#![allow(deprecated)]
8use crate::User;
9use crate::{Permission, PermissionContext};
10use async_trait::async_trait;
11use std::collections::HashMap;
12use std::sync::Arc;
13use tokio::sync::RwLock;
14
15pub type PermissionMap = Arc<RwLock<HashMap<(String, String), Vec<String>>>>;
18
19#[async_trait]
64pub trait ObjectPermissionChecker: Send + Sync {
65 async fn has_object_permission(
77 &self,
78 user: &dyn User,
79 object_id: &str,
80 permission: &str,
81 ) -> bool;
82}
83
84pub struct ObjectPermissionManager {
121 permissions: PermissionMap,
123}
124
125impl ObjectPermissionManager {
126 pub fn new() -> Self {
136 Self {
137 permissions: Arc::new(RwLock::new(HashMap::new())),
138 }
139 }
140
141 pub async fn grant_permission(&mut self, username: &str, object_id: &str, permission: &str) {
156 let mut perms = self.permissions.write().await;
157 let key = (username.to_string(), object_id.to_string());
158 perms.entry(key).or_default().push(permission.to_string());
159 }
160
161 pub async fn revoke_permission(&mut self, username: &str, object_id: &str, permission: &str) {
176 let mut perms = self.permissions.write().await;
177 let key = (username.to_string(), object_id.to_string());
178 if let Some(user_perms) = perms.get_mut(&key) {
179 user_perms.retain(|p| p != permission);
180 if user_perms.is_empty() {
181 perms.remove(&key);
182 }
183 }
184 }
185
186 pub async fn revoke_all_permissions(&mut self, username: &str, object_id: &str) {
202 let mut perms = self.permissions.write().await;
203 let key = (username.to_string(), object_id.to_string());
204 perms.remove(&key);
205 }
206
207 pub async fn list_permissions(&self, username: &str, object_id: &str) -> Vec<String> {
225 let perms = self.permissions.read().await;
226 let key = (username.to_string(), object_id.to_string());
227 perms.get(&key).cloned().unwrap_or_default()
228 }
229}
230
231impl Default for ObjectPermissionManager {
232 fn default() -> Self {
233 Self::new()
234 }
235}
236
237#[async_trait]
238impl ObjectPermissionChecker for ObjectPermissionManager {
239 async fn has_object_permission(
240 &self,
241 user: &dyn User,
242 object_id: &str,
243 permission: &str,
244 ) -> bool {
245 let perms = self.permissions.read().await;
246 let key = (user.username().to_string(), object_id.to_string());
247 if let Some(user_perms) = perms.get(&key) {
248 return user_perms.iter().any(|p| p == permission);
249 }
250 false
251 }
252}
253
254pub struct ObjectPermission<T: ObjectPermissionChecker + Send + Sync> {
305 checker: T,
306 object_id: String,
307 permission: String,
308}
309
310impl<T: ObjectPermissionChecker + Send + Sync> ObjectPermission<T> {
311 pub fn new(checker: T, object_id: impl Into<String>, permission: impl Into<String>) -> Self {
322 Self {
323 checker,
324 object_id: object_id.into(),
325 permission: permission.into(),
326 }
327 }
328}
329
330#[async_trait]
331impl<T: ObjectPermissionChecker + Send + Sync> Permission for ObjectPermission<T> {
332 async fn has_permission(&self, context: &PermissionContext<'_>) -> bool {
333 if !context.is_authenticated {
334 return false;
335 }
336
337 if let Some(ref user) = context.user {
338 return self
339 .checker
340 .has_object_permission(user.as_ref(), &self.object_id, &self.permission)
341 .await;
342 }
343
344 false
345 }
346}
347
348#[cfg(test)]
349mod tests {
350 use super::*;
351 use crate::SimpleUser;
352 use bytes::Bytes;
353 use hyper::Method;
354 use reinhardt_http::Request;
355 use rstest::rstest;
356 use uuid::Uuid;
357
358 #[tokio::test]
359 async fn test_object_permission_manager_grant() {
360 let mut manager = ObjectPermissionManager::new();
361 manager
362 .grant_permission("alice", "article:123", "view")
363 .await;
364 manager
365 .grant_permission("alice", "article:123", "change")
366 .await;
367
368 let user = SimpleUser {
369 id: Uuid::new_v4(),
370 username: "alice".to_string(),
371 email: "alice@example.com".to_string(),
372 is_active: true,
373 is_admin: false,
374 is_staff: false,
375 is_superuser: false,
376 };
377
378 assert!(
379 manager
380 .has_object_permission(&user, "article:123", "view")
381 .await
382 );
383 assert!(
384 manager
385 .has_object_permission(&user, "article:123", "change")
386 .await
387 );
388 assert!(
389 !manager
390 .has_object_permission(&user, "article:123", "delete")
391 .await
392 );
393 }
394
395 #[tokio::test]
396 async fn test_object_permission_manager_revoke() {
397 let mut manager = ObjectPermissionManager::new();
398 manager
399 .grant_permission("alice", "article:123", "view")
400 .await;
401 manager
402 .grant_permission("alice", "article:123", "change")
403 .await;
404
405 let user = SimpleUser {
406 id: Uuid::new_v4(),
407 username: "alice".to_string(),
408 email: "alice@example.com".to_string(),
409 is_active: true,
410 is_admin: false,
411 is_staff: false,
412 is_superuser: false,
413 };
414
415 manager
416 .revoke_permission("alice", "article:123", "view")
417 .await;
418
419 assert!(
420 !manager
421 .has_object_permission(&user, "article:123", "view")
422 .await
423 );
424 assert!(
425 manager
426 .has_object_permission(&user, "article:123", "change")
427 .await
428 );
429 }
430
431 #[tokio::test]
432 async fn test_object_permission_manager_revoke_all() {
433 let mut manager = ObjectPermissionManager::new();
434 manager
435 .grant_permission("alice", "article:123", "view")
436 .await;
437 manager
438 .grant_permission("alice", "article:123", "change")
439 .await;
440
441 let user = SimpleUser {
442 id: Uuid::new_v4(),
443 username: "alice".to_string(),
444 email: "alice@example.com".to_string(),
445 is_active: true,
446 is_admin: false,
447 is_staff: false,
448 is_superuser: false,
449 };
450
451 manager.revoke_all_permissions("alice", "article:123").await;
452
453 assert!(
454 !manager
455 .has_object_permission(&user, "article:123", "view")
456 .await
457 );
458 assert!(
459 !manager
460 .has_object_permission(&user, "article:123", "change")
461 .await
462 );
463 }
464
465 #[tokio::test]
466 async fn test_object_permission_manager_list() {
467 let mut manager = ObjectPermissionManager::new();
468 manager
469 .grant_permission("alice", "article:123", "view")
470 .await;
471 manager
472 .grant_permission("alice", "article:123", "change")
473 .await;
474
475 let perms = manager.list_permissions("alice", "article:123").await;
476 assert_eq!(perms.len(), 2);
477 assert!(perms.contains(&"view".to_string()));
478 assert!(perms.contains(&"change".to_string()));
479 }
480
481 #[tokio::test]
482 async fn test_object_permission_manager_different_objects() {
483 let mut manager = ObjectPermissionManager::new();
484 manager
485 .grant_permission("alice", "article:123", "view")
486 .await;
487 manager
488 .grant_permission("alice", "article:456", "change")
489 .await;
490
491 let user = SimpleUser {
492 id: Uuid::new_v4(),
493 username: "alice".to_string(),
494 email: "alice@example.com".to_string(),
495 is_active: true,
496 is_admin: false,
497 is_staff: false,
498 is_superuser: false,
499 };
500
501 assert!(
502 manager
503 .has_object_permission(&user, "article:123", "view")
504 .await
505 );
506 assert!(
507 !manager
508 .has_object_permission(&user, "article:123", "change")
509 .await
510 );
511 assert!(
512 !manager
513 .has_object_permission(&user, "article:456", "view")
514 .await
515 );
516 assert!(
517 manager
518 .has_object_permission(&user, "article:456", "change")
519 .await
520 );
521 }
522
523 #[tokio::test]
524 async fn test_object_permission_trait_authenticated() {
525 let mut manager = ObjectPermissionManager::new();
526 manager
527 .grant_permission("alice", "article:123", "view")
528 .await;
529
530 let perm = ObjectPermission::new(manager, "article:123", "view");
531
532 let user = SimpleUser {
533 id: Uuid::new_v4(),
534 username: "alice".to_string(),
535 email: "alice@example.com".to_string(),
536 is_active: true,
537 is_admin: false,
538 is_staff: false,
539 is_superuser: false,
540 };
541
542 let request = Request::builder()
543 .method(Method::GET)
544 .uri("/")
545 .body(Bytes::new())
546 .build()
547 .unwrap();
548
549 let context = PermissionContext {
550 request: &request,
551 is_authenticated: true,
552 is_admin: false,
553 is_active: true,
554 user: Some(Box::new(user)),
555 };
556
557 assert!(perm.has_permission(&context).await);
558 }
559
560 #[tokio::test]
561 async fn test_object_permission_trait_unauthenticated() {
562 let manager = ObjectPermissionManager::new();
563 let perm = ObjectPermission::new(manager, "article:123", "view");
564
565 let request = Request::builder()
566 .method(Method::GET)
567 .uri("/")
568 .body(Bytes::new())
569 .build()
570 .unwrap();
571
572 let context = PermissionContext {
573 request: &request,
574 is_authenticated: false,
575 is_admin: false,
576 is_active: false,
577 user: None,
578 };
579
580 assert!(!perm.has_permission(&context).await);
581 }
582
583 #[tokio::test]
584 async fn test_object_permission_trait_no_permission() {
585 let manager = ObjectPermissionManager::new();
586 let perm = ObjectPermission::new(manager, "article:123", "delete");
587
588 let user = SimpleUser {
589 id: Uuid::new_v4(),
590 username: "alice".to_string(),
591 email: "alice@example.com".to_string(),
592 is_active: true,
593 is_admin: false,
594 is_staff: false,
595 is_superuser: false,
596 };
597
598 let request = Request::builder()
599 .method(Method::DELETE)
600 .uri("/")
601 .body(Bytes::new())
602 .build()
603 .unwrap();
604
605 let context = PermissionContext {
606 request: &request,
607 is_authenticated: true,
608 is_admin: false,
609 is_active: true,
610 user: Some(Box::new(user)),
611 };
612
613 assert!(!perm.has_permission(&context).await);
614 }
615
616 #[rstest]
617 #[tokio::test]
618 async fn test_bulk_check_multiple_objects() {
619 let mut manager = ObjectPermissionManager::new();
621 manager.grant_permission("alice", "article:1", "view").await;
622 manager
623 .grant_permission("alice", "article:2", "change")
624 .await;
625 let user = SimpleUser {
628 id: Uuid::new_v4(),
629 username: "alice".to_string(),
630 email: "alice@example.com".to_string(),
631 is_active: true,
632 is_admin: false,
633 is_staff: false,
634 is_superuser: false,
635 };
636
637 let result_obj1 = manager
639 .has_object_permission(&user, "article:1", "view")
640 .await;
641 let result_obj2 = manager
642 .has_object_permission(&user, "article:2", "change")
643 .await;
644 let result_obj3 = manager
645 .has_object_permission(&user, "article:3", "view")
646 .await;
647
648 assert!(result_obj1);
650 assert!(result_obj2);
651 assert!(!result_obj3);
652 }
653
654 #[rstest]
655 #[tokio::test]
656 async fn test_different_users_same_object() {
657 let mut manager = ObjectPermissionManager::new();
659 manager
660 .grant_permission("alice", "article:42", "view")
661 .await;
662
663 let user_a = SimpleUser {
664 id: Uuid::new_v4(),
665 username: "alice".to_string(),
666 email: "alice@example.com".to_string(),
667 is_active: true,
668 is_admin: false,
669 is_staff: false,
670 is_superuser: false,
671 };
672 let user_b = SimpleUser {
673 id: Uuid::new_v4(),
674 username: "bob".to_string(),
675 email: "bob@example.com".to_string(),
676 is_active: true,
677 is_admin: false,
678 is_staff: false,
679 is_superuser: false,
680 };
681
682 let result_a = manager
684 .has_object_permission(&user_a, "article:42", "view")
685 .await;
686 let result_b = manager
687 .has_object_permission(&user_b, "article:42", "view")
688 .await;
689
690 assert!(result_a);
692 assert!(!result_b);
693 }
694}