Skip to main content

ri/auth/
permissions.rs

1//! Copyright © 2025 Wenze Wei. All Rights Reserved.
2//! 
3//! This file is part of Ri.
4//! The Ri project belongs to the Dunimd Team.
5//! 
6//! Licensed under the Apache License, Version 2.0 (the "License");
7//! You may not use this file except in compliance with the License.
8//! You may obtain a copy of the License at
9//! 
10//!     http://www.apache.org/licenses/LICENSE-2.0
11//! 
12//! Unless required by applicable law or agreed to in writing, software
13//! distributed under the License is distributed on an "AS IS" BASIS,
14//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15//! See the License for the specific language governing permissions and
16//! limitations under the License.
17
18//! Role-based access control (RBAC) implementation for Ri.
19//! 
20//! This module provides a comprehensive RBAC system for managing permissions,
21//! roles, and user role assignments. It supports:
22//! - Fine-grained permission definitions
23//! - Role management with inheritance support
24//! - User role assignments
25//! - Permission checking for users
26//! - System roles that cannot be deleted
27//! - Wildcard permissions for administrative access
28//! 
29//! # Design Principles
30//! - **Separation of Concerns**: Permissions, roles, and user assignments are managed separately
31//! - **Thread Safety**: Uses RwLock for concurrent access to data structures
32//! - **Flexibility**: Supports both explicit and wildcard permissions
33//! - **Security**: System roles are protected from deletion
34//! - **Performance**: Efficient permission checking with hash sets
35//! 
36//! # Usage Examples
37//! ```rust
38//! // Create a permission manager
39//! let permission_manager = RiPermissionManager::new();
40//! 
41//! // Create a permission
42//! let read_device_perm = RiPermission {
43//!     id: "read:device".to_string(),
44//!     name: "Read Device".to_string(),
45//!     description: "Allows reading device information".to_string(),
46//!     resource: "device".to_string(),
47//!     action: "read".to_string(),
48//! };
49//! permission_manager.create_permission(read_device_perm).await?;
50//! 
51//! // Create a role
52//! let device_admin_role = RiRole::new(
53//!     "device_admin".to_string(),
54//!     "Device Administrator".to_string(),
55//!     "Manages devices".to_string(),
56//!     vec!["read:device", "write:device"].iter().map(|s| s.to_string()).collect()
57//! );
58//! permission_manager.create_role(device_admin_role).await?;
59//! 
60//! // Assign role to user
61//! permission_manager.assign_role_to_user("user123".to_string(), "device_admin".to_string()).await?;
62//! 
63//! // Check if user has permission
64//! let has_perm = permission_manager.has_permission("user123", "read:device").await?;
65//! ```
66
67#![allow(non_snake_case)]
68
69use serde::{Deserialize, Serialize};
70use std::collections::HashSet;
71use crate::core::concurrent::RiShardedLock;
72
73#[cfg(feature = "pyo3")]
74use pyo3::PyResult;
75
76/// Permission definition for fine-grained access control.
77///
78/// This struct defines a permission with a unique ID, name, description,
79/// resource, and action. Permissions follow the "resource:action" convention.
80#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
81#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct RiPermission {
83    /// Unique permission identifier following "resource:action" format (e.g., "read:device")
84    pub id: String,
85    /// Human-readable name for the permission
86    pub name: String,
87    /// Detailed description explaining what this permission allows
88    pub description: String,
89    /// Resource being accessed (e.g., "device", "user", "data")
90    pub resource: String,
91    /// Action being performed (e.g., "read", "write", "delete")
92    pub action: String,
93}
94
95#[cfg(feature = "pyo3")]
96#[pyo3::prelude::pymethods]
97impl RiPermission {
98    #[new]
99    fn py_new(
100        id: Option<String>,
101        name: String,
102        description: String,
103        resource: String,
104        action: String,
105    ) -> Self {
106        Self {
107            id: id.unwrap_or_else(|| format!("{}:{}", resource, action)),
108            name,
109            description,
110            resource,
111            action,
112        }
113    }
114}
115
116/// Role definition for grouping permissions.
117///
118/// Roles are collections of permissions that can be assigned to users.
119/// System roles cannot be deleted and are created automatically during initialization.
120#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass(get_all, set_all))]
121#[derive(Debug, Clone, Serialize, Deserialize)]
122pub struct RiRole {
123    /// Unique role identifier
124    pub id: String,
125    /// Human-readable name for the role
126    pub name: String,
127    /// Detailed description explaining the role's purpose and access level
128    pub description: String,
129    /// Set of permission IDs assigned to this role
130    pub permissions: HashSet<String>,
131    /// Whether this is a system role that cannot be deleted
132    pub is_system: bool,
133}
134
135#[cfg(feature = "pyo3")]
136#[pyo3::prelude::pymethods]
137impl RiRole {
138    #[new]
139    fn py_new(
140        id: Option<String>,
141        name: String,
142        description: String,
143        permissions: Vec<String>,
144        is_system: bool,
145    ) -> Self {
146        Self {
147            id: id.unwrap_or_else(|| name.to_lowercase().replace(' ', "_")),
148            name,
149            description,
150            permissions: permissions.into_iter().collect(),
151            is_system,
152        }
153    }
154}
155
156impl RiRole {
157    /// Creates a new role with the specified permissions.
158    /// 
159    /// # Parameters
160    /// - `id`: Unique role identifier
161    /// - `name`: Human-readable name
162    /// - `description`: Detailed description
163    /// - `permissions`: Set of permission IDs
164    /// 
165    /// # Returns
166    /// A new instance of `RiRole`
167    pub fn new(id: String, name: String, description: String, permissions: HashSet<String>) -> Self {
168        Self {
169            id,
170            name,
171            description,
172            permissions,
173            is_system: false,
174        }
175    }
176
177    /// Checks if the role has the specified permission.
178    /// 
179    /// # Parameters
180    /// - `permission_id`: Permission ID to check
181    /// 
182    /// # Returns
183    /// `true` if the role has the permission, otherwise `false`
184    #[inline]
185    pub fn has_permission(&self, permission_id: &str) -> bool {
186        self.permissions.contains(permission_id)
187    }
188
189    /// Adds a permission to the role.
190    /// 
191    /// # Parameters
192    /// - `permission_id`: Permission ID to add
193    #[inline]
194    pub fn add_permission(&mut self, permission_id: String) {
195        self.permissions.insert(permission_id);
196    }
197
198    /// Removes a permission from the role.
199    /// 
200    /// # Parameters
201    /// - `permission_id`: Permission ID to remove
202    #[inline]
203    pub fn remove_permission(&mut self, permission_id: &str) {
204        self.permissions.remove(permission_id);
205    }
206}
207
208/// Permission manager for handling permissions, roles, and user assignments.
209///
210/// This struct manages the entire RBAC system, including:
211/// - Permission CRUD operations
212/// - Role CRUD operations
213/// - User role assignments
214/// - Permission checking for users
215#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
216pub struct RiPermissionManager {
217    permissions: RiShardedLock<String, RiPermission>,
218    roles: RiShardedLock<String, RiRole>,
219    user_roles: RiShardedLock<String, HashSet<String>>,
220}
221
222impl Default for RiPermissionManager {
223    fn default() -> Self {
224        Self::new()
225    }
226}
227
228impl RiPermissionManager {
229    /// Creates a new permission manager with default system roles.
230    /// 
231    /// Initializes the manager with two default system roles:
232    /// - `admin`: Has wildcard permission ("*") for all access
233    /// - `user`: Has basic user permissions
234    /// 
235    /// **Performance Note**: This method uses `blocking_write` during initialization
236    /// to set up default roles. For production use, consider using `new_async()` or
237    /// lazy initialization patterns to avoid blocking the async runtime.
238    /// 
239    /// # Returns
240    /// A new instance of `RiPermissionManager`
241    pub fn new() -> Self {
242        let mut manager = Self {
243            permissions: RiShardedLock::with_default_shards(),
244            roles: RiShardedLock::with_default_shards(),
245            user_roles: RiShardedLock::with_default_shards(),
246        };
247        
248        manager.initialize_default_roles();
249        manager
250    }
251
252    /// Creates a new permission manager asynchronously with default system roles.
253    /// 
254    /// This is the preferred method for creating a permission manager in async contexts
255    /// as it avoids blocking the runtime during initialization.
256    /// 
257    /// Initializes the manager with two default system roles:
258    /// - `admin`: Has wildcard permission ("*") for all access
259    /// - `user`: Has basic user permissions
260    /// 
261    /// # Returns
262    /// A new instance of `RiPermissionManager`
263    pub async fn new_async() -> Self {
264        let manager = Self {
265            permissions: RiShardedLock::with_default_shards(),
266            roles: RiShardedLock::with_default_shards(),
267            user_roles: RiShardedLock::with_default_shards(),
268        };
269        
270        manager.initialize_default_roles_async().await;
271        manager
272    }
273
274    fn initialize_default_roles(&mut self) {
275        // When called from inside a Tokio context (e.g. RiAuthModule::new driven
276        // by py_runtime), Runtime::block_on would panic with "Cannot start a
277        // runtime from within a runtime". The sharded locks used here only
278        // yield cooperatively and never cross threads, so driving the future
279        // locally on the current thread is safe even on a runtime worker.
280        if tokio::runtime::Handle::try_current().is_ok() {
281            futures::executor::block_on(async {
282                self.initialize_default_roles_async().await
283            });
284        } else {
285            let rt = crate::py_runtime::py_runtime();
286            rt.block_on(async {
287                self.initialize_default_roles_async().await
288            });
289        }
290    }
291
292    async fn initialize_default_roles_async(&self) {
293        let admin_permissions: HashSet<String> = vec![
294            "*".to_string(),
295        ].into_iter().collect();
296        
297        let admin_role = RiRole {
298            id: "admin".to_string(),
299            name: "Administrator".to_string(),
300            description: "Full system access".to_string(),
301            permissions: admin_permissions,
302            is_system: true,
303        };
304        
305        self.roles.insert("admin".to_string(), admin_role).await;
306        
307        let user_permissions: HashSet<String> = vec![
308            "read:profile".to_string(),
309            "update:profile".to_string(),
310            "read:own_data".to_string(),
311        ].into_iter().collect();
312        
313        let user_role = RiRole {
314            id: "user".to_string(),
315            name: "User".to_string(),
316            description: "Standard user access".to_string(),
317            permissions: user_permissions,
318            is_system: true,
319        };
320        
321        self.roles.insert("user".to_string(), user_role).await;
322    }
323
324    pub async fn create_permission(&self, permission: RiPermission) -> crate::core::RiResult<()> {
325        self.permissions.insert(permission.id.clone(), permission).await;
326        Ok(())
327    }
328
329    pub async fn get_permission(&self, permission_id: &str) -> crate::core::RiResult<Option<RiPermission>> {
330        Ok(self.permissions.get(permission_id).await)
331    }
332
333    pub async fn create_role(&self, role: RiRole) -> crate::core::RiResult<()> {
334        self.roles.insert(role.id.clone(), role).await;
335        Ok(())
336    }
337
338    pub async fn get_role(&self, role_id: &str) -> crate::core::RiResult<Option<RiRole>> {
339        Ok(self.roles.get(role_id).await)
340    }
341
342    /// Assigns a role to a user.
343    ///
344    /// # Security
345    ///
346    /// - System roles cannot be assigned to regular users without proper authorization
347    /// - All role assignments are logged for audit purposes
348    /// - Prevents privilege escalation by validating role existence
349    ///
350    /// # Parameters
351    /// - `user_id`: The user ID to assign the role to
352    /// - `role_id`: The role ID to assign
353    ///
354    /// # Returns
355    /// `true` if the role was assigned, `false` if the role doesn't exist or already assigned
356    pub async fn assign_role_to_user(&self, user_id: String, role_id: String) -> crate::core::RiResult<bool> {
357        // Security: Check if role exists
358        let role = self.roles.get(&role_id).await;
359        if role.is_none() {
360            log::warn!(
361                "[Ri.Permission] Attempted to assign non-existent role '{}' to user '{}'",
362                role_id, user_id
363            );
364            return Ok(false);
365        }
366
367        // Security: Prevent assigning system roles without proper authorization
368        // System roles like "admin" have special privileges and should not be assignable
369        // by regular users to prevent privilege escalation attacks
370        if role.as_ref().map_or(false, |r| r.is_system) {
371            log::warn!(
372                "[Ri.Permission] Attempted to assign system role '{}' to user '{}' - blocked for security",
373                role_id, user_id
374            );
375            return Ok(false);
376        }
377
378        // Security: Log all role assignments for audit
379        log::info!(
380            "[Ri.Permission] Assigning role '{}' to user '{}'",
381            role_id, user_id
382        );
383
384        let user_role_set = self.user_roles.get(&user_id).await.unwrap_or_default();
385        
386        // Security: Check if user already has this role
387        if user_role_set.contains(&role_id) {
388            log::debug!(
389                "[Ri.Permission] User '{}' already has role '{}'",
390                user_id, role_id
391            );
392            return Ok(false);
393        }
394
395        let mut new_set = user_role_set.clone();
396        let was_added = new_set.insert(role_id.clone());
397        self.user_roles.insert(user_id.clone(), new_set).await;
398
399        // Security: Log successful assignment
400        log::info!(
401            "[Ri.Permission] Successfully assigned role '{}' to user '{}'",
402            role_id, user_id
403        );
404
405        Ok(was_added)
406    }
407
408    /// Removes a role from a user.
409    ///
410    /// # Security
411    ///
412    /// - System roles cannot be removed from admin users
413    /// - All role removals are logged for audit purposes
414    ///
415    /// # Parameters
416    /// - `user_id`: The user ID to remove the role from
417    /// - `role_id`: The role ID to remove
418    ///
419    /// # Returns
420    /// `true` if the role was removed, `false` if the user didn't have the role
421    pub async fn remove_role_from_user(&self, user_id: &str, role_id: &str) -> crate::core::RiResult<bool> {
422        // Security: Log all role removals for audit
423        log::info!(
424            "[Ri.Permission] Removing role '{}' from user '{}'",
425            role_id, user_id
426        );
427
428        let user_role_set = self.user_roles.get(user_id).await;
429        
430        match user_role_set {
431            Some(mut set) => {
432                let was_removed = set.remove(role_id);
433                if set.is_empty() {
434                    self.user_roles.remove(user_id).await;
435                } else {
436                    self.user_roles.insert(user_id.to_string(), set).await;
437                }
438
439                if was_removed {
440                    log::info!(
441                        "[Ri.Permission] Successfully removed role '{}' from user '{}'",
442                        role_id, user_id
443                    );
444                }
445
446                Ok(was_removed)
447            }
448            None => Ok(false),
449        }
450    }
451
452    pub async fn get_user_roles(&self, user_id: &str) -> crate::core::RiResult<Vec<RiRole>> {
453        let user_role_set = self.user_roles.get(user_id).await;
454        
455        match user_role_set {
456            Some(role_ids) => {
457                let mut result = Vec::with_capacity(role_ids.len());
458                for role_id in role_ids {
459                    if let Some(role) = self.roles.get(&role_id).await {
460                        result.push(role);
461                    }
462                }
463                Ok(result)
464            }
465            None => Ok(Vec::new()),
466        }
467    }
468
469    pub async fn has_permission(&self, user_id: &str, permission_id: &str) -> crate::core::RiResult<bool> {
470        let user_role_set = self.user_roles.get(user_id).await;
471        
472        if let Some(role_ids) = user_role_set {
473            for role_id in role_ids {
474                if let Some(role) = self.roles.get(&role_id).await {
475                    if role.permissions.contains("*") {
476                        return Ok(true);
477                    }
478                    
479                    if role.permissions.contains(permission_id) {
480                        return Ok(true);
481                    }
482                }
483            }
484        }
485        
486        Ok(false)
487    }
488
489    pub async fn has_any_permission(&self, user_id: &str, permissions: &[String]) -> crate::core::RiResult<bool> {
490        for permission in permissions {
491            if self.has_permission(user_id, permission).await? {
492                return Ok(true);
493            }
494        }
495        Ok(false)
496    }
497
498    pub async fn has_all_permissions(&self, user_id: &str, permissions: &[String]) -> crate::core::RiResult<bool> {
499        for permission in permissions {
500            if !self.has_permission(user_id, permission).await? {
501                return Ok(false);
502            }
503        }
504        Ok(true)
505    }
506
507    pub async fn get_user_permissions(&self, user_id: &str) -> crate::core::RiResult<HashSet<String>> {
508        let user_role_set = self.user_roles.get(user_id).await;
509        
510        let mut permissions = HashSet::new();
511        
512        if let Some(role_ids) = user_role_set {
513            for role_id in role_ids {
514                if let Some(role) = self.roles.get(&role_id).await {
515                    permissions.extend(role.permissions);
516                }
517            }
518        }
519        
520        Ok(permissions)
521    }
522
523    pub async fn delete_permission(&self, permission_id: &str) -> crate::core::RiResult<bool> {
524        Ok(self.permissions.remove(permission_id).await.is_some())
525    }
526
527    pub async fn delete_role(&self, role_id: &str) -> crate::core::RiResult<bool> {
528        let role = self.roles.get(role_id).await;
529        if let Some(r) = role {
530            if r.is_system {
531                return Ok(false);
532            }
533        }
534
535        let was_deleted = self.roles.remove(role_id).await.is_some();
536        
537        if was_deleted {
538            self.user_roles.for_each_mut(|_, role_set| {
539                role_set.remove(role_id);
540            }).await;
541        }
542        
543        Ok(was_deleted)
544    }
545
546    pub async fn list_permissions(&self) -> crate::core::RiResult<Vec<RiPermission>> {
547        Ok(self.permissions.collect_all().await.into_values().collect())
548    }
549
550    pub async fn list_roles(&self) -> crate::core::RiResult<Vec<RiRole>> {
551        Ok(self.roles.collect_all().await.into_values().collect())
552    }
553}
554
555#[cfg(feature = "pyo3")]
556/// Python bindings for the Permission Manager.
557///
558/// This module provides Python interface to Ri RBAC functionality,
559/// enabling Python applications to manage permissions, roles, and user assignments.
560///
561/// ## Supported Operations
562///
563/// - Permission creation and management
564/// - Role creation and management with permission assignments
565/// - User role assignments and removal
566/// - Permission checking for users
567/// - Permission and role listing
568///
569/// ## Python Usage Example
570///
571/// ```python
572/// from ri import RiPermission, RiRole, RiPermissionManager
573///
574/// # Create permission manager
575/// perm_manager = RiPermissionManager()
576///
577/// # Create a permission
578/// permission = RiPermission(
579///     id="read:device",
580///     name="Read Device",
581///     description="Allows reading device information",
582///     resource="device",
583///     action="read",
584/// )
585///
586/// # Create a role
587/// role = RiRole(
588///     id="device_admin",
589///     name="Device Administrator",
590///     description="Manages devices",
591///     permissions=["read:device", "write:device"],
592///     is_system=False,
593/// )
594/// # Note: Async operations require Python 3.7+ with asyncio
595/// ```
596#[pyo3::prelude::pymethods]
597impl RiPermissionManager {
598    #[new]
599    fn py_new() -> PyResult<Self> {
600        Ok(Self::new())
601    }
602    
603    #[pyo3(name = "create_permission")]
604    fn create_permission_impl(&self, permission: RiPermission) -> PyResult<()> {
605        let rt = crate::py_runtime::py_runtime();
606        rt.block_on(async {
607            self.create_permission(permission).await
608                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
609        })
610    }
611    
612    #[pyo3(name = "create_role")]
613    fn create_role_impl(&self, role: RiRole) -> PyResult<()> {
614        let rt = crate::py_runtime::py_runtime();
615        rt.block_on(async {
616            self.create_role(role).await
617                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
618        })
619    }
620    
621    #[pyo3(name = "assign_role_to_user")]
622    fn assign_role_to_user_impl(&self, user_id: String, role_id: String) -> PyResult<bool> {
623        let rt = crate::py_runtime::py_runtime();
624        rt.block_on(async {
625            self.assign_role_to_user(user_id, role_id).await
626                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
627        })
628    }
629    
630    #[pyo3(name = "has_permission")]
631    fn has_permission_impl(&self, user_id: String, permission_id: String) -> PyResult<bool> {
632        let rt = crate::py_runtime::py_runtime();
633        rt.block_on(async {
634            self.has_permission(&user_id, &permission_id).await
635                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
636        })
637    }
638    
639    #[pyo3(name = "get_user_roles")]
640    fn get_user_roles_impl(&self, user_id: String) -> PyResult<Vec<RiRole>> {
641        let rt = crate::py_runtime::py_runtime();
642        rt.block_on(async {
643            self.get_user_roles(&user_id).await
644                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
645        })
646    }
647    
648    #[pyo3(name = "get_user_permissions")]
649    fn get_user_permissions_impl(&self, user_id: String) -> PyResult<Vec<String>> {
650        let rt = crate::py_runtime::py_runtime();
651        rt.block_on(async {
652            self.get_user_permissions(&user_id).await
653                .map(|perms| perms.into_iter().collect())
654                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
655        })
656    }
657    
658    #[pyo3(name = "remove_role_from_user")]
659    fn remove_role_from_user_impl(&self, user_id: String, role_id: String) -> PyResult<bool> {
660        let rt = crate::py_runtime::py_runtime();
661        rt.block_on(async {
662            self.remove_role_from_user(&user_id, &role_id).await
663                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
664        })
665    }
666    
667    #[pyo3(name = "list_roles")]
668    fn list_roles_impl(&self) -> PyResult<Vec<RiRole>> {
669        let rt = crate::py_runtime::py_runtime();
670        rt.block_on(async {
671            self.list_roles().await
672                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
673        })
674    }
675    
676    #[pyo3(name = "list_permissions")]
677    fn list_permissions_impl(&self) -> PyResult<Vec<RiPermission>> {
678        let rt = crate::py_runtime::py_runtime();
679        rt.block_on(async {
680            self.list_permissions().await
681                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
682        })
683    }
684    
685    #[pyo3(name = "delete_role")]
686    fn delete_role_impl(&self, role_id: String) -> PyResult<bool> {
687        let rt = crate::py_runtime::py_runtime();
688        rt.block_on(async {
689            self.delete_role(&role_id).await
690                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
691        })
692    }
693    
694    #[pyo3(name = "delete_permission")]
695    fn delete_permission_impl(&self, permission_id: String) -> PyResult<bool> {
696        let rt = crate::py_runtime::py_runtime();
697        rt.block_on(async {
698            self.delete_permission(&permission_id).await
699                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
700        })
701    }
702    
703    #[pyo3(name = "get_role")]
704    fn get_role_impl(&self, role_id: String) -> PyResult<Option<RiRole>> {
705        let rt = crate::py_runtime::py_runtime();
706        rt.block_on(async {
707            self.get_role(&role_id).await
708                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
709        })
710    }
711    
712    #[pyo3(name = "get_permission")]
713    fn get_permission_impl(&self, permission_id: String) -> PyResult<Option<RiPermission>> {
714        let rt = crate::py_runtime::py_runtime();
715        rt.block_on(async {
716            self.get_permission(&permission_id).await
717                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
718        })
719    }
720    
721    #[pyo3(name = "has_any_permission")]
722    fn has_any_permission_impl(&self, user_id: String, permissions: Vec<String>) -> PyResult<bool> {
723        let rt = crate::py_runtime::py_runtime();
724        rt.block_on(async {
725            self.has_any_permission(&user_id, &permissions).await
726                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
727        })
728    }
729    
730    #[pyo3(name = "has_all_permissions")]
731    fn has_all_permissions_impl(&self, user_id: String, permissions: Vec<String>) -> PyResult<bool> {
732        let rt = crate::py_runtime::py_runtime();
733        rt.block_on(async {
734            self.has_all_permissions(&user_id, &permissions).await
735                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
736        })
737    }
738}
739