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        let rt = tokio::runtime::Runtime::new().expect("Failed to create tokio runtime");
276        rt.block_on(async {
277            self.initialize_default_roles_async().await
278        });
279    }
280
281    async fn initialize_default_roles_async(&self) {
282        let admin_permissions: HashSet<String> = vec![
283            "*".to_string(),
284        ].into_iter().collect();
285        
286        let admin_role = RiRole {
287            id: "admin".to_string(),
288            name: "Administrator".to_string(),
289            description: "Full system access".to_string(),
290            permissions: admin_permissions,
291            is_system: true,
292        };
293        
294        self.roles.insert("admin".to_string(), admin_role).await;
295        
296        let user_permissions: HashSet<String> = vec![
297            "read:profile".to_string(),
298            "update:profile".to_string(),
299            "read:own_data".to_string(),
300        ].into_iter().collect();
301        
302        let user_role = RiRole {
303            id: "user".to_string(),
304            name: "User".to_string(),
305            description: "Standard user access".to_string(),
306            permissions: user_permissions,
307            is_system: true,
308        };
309        
310        self.roles.insert("user".to_string(), user_role).await;
311    }
312
313    pub async fn create_permission(&self, permission: RiPermission) -> crate::core::RiResult<()> {
314        self.permissions.insert(permission.id.clone(), permission).await;
315        Ok(())
316    }
317
318    pub async fn get_permission(&self, permission_id: &str) -> crate::core::RiResult<Option<RiPermission>> {
319        Ok(self.permissions.get(permission_id).await)
320    }
321
322    pub async fn create_role(&self, role: RiRole) -> crate::core::RiResult<()> {
323        self.roles.insert(role.id.clone(), role).await;
324        Ok(())
325    }
326
327    pub async fn get_role(&self, role_id: &str) -> crate::core::RiResult<Option<RiRole>> {
328        Ok(self.roles.get(role_id).await)
329    }
330
331    /// Assigns a role to a user.
332    ///
333    /// # Security
334    ///
335    /// - System roles cannot be assigned to regular users without proper authorization
336    /// - All role assignments are logged for audit purposes
337    /// - Prevents privilege escalation by validating role existence
338    ///
339    /// # Parameters
340    /// - `user_id`: The user ID to assign the role to
341    /// - `role_id`: The role ID to assign
342    ///
343    /// # Returns
344    /// `true` if the role was assigned, `false` if the role doesn't exist or already assigned
345    pub async fn assign_role_to_user(&self, user_id: String, role_id: String) -> crate::core::RiResult<bool> {
346        // Security: Check if role exists
347        let role = self.roles.get(&role_id).await;
348        if role.is_none() {
349            log::warn!(
350                "[Ri.Permission] Attempted to assign non-existent role '{}' to user '{}'",
351                role_id, user_id
352            );
353            return Ok(false);
354        }
355
356        // Security: Prevent assigning system roles without proper authorization
357        // System roles like "admin" have special privileges and should not be assignable
358        // by regular users to prevent privilege escalation attacks
359        if role.as_ref().map_or(false, |r| r.is_system) {
360            log::warn!(
361                "[Ri.Permission] Attempted to assign system role '{}' to user '{}' - blocked for security",
362                role_id, user_id
363            );
364            return Ok(false);
365        }
366
367        // Security: Log all role assignments for audit
368        log::info!(
369            "[Ri.Permission] Assigning role '{}' to user '{}'",
370            role_id, user_id
371        );
372
373        let user_role_set = self.user_roles.get(&user_id).await.unwrap_or_default();
374        
375        // Security: Check if user already has this role
376        if user_role_set.contains(&role_id) {
377            log::debug!(
378                "[Ri.Permission] User '{}' already has role '{}'",
379                user_id, role_id
380            );
381            return Ok(false);
382        }
383
384        let mut new_set = user_role_set.clone();
385        let was_added = new_set.insert(role_id.clone());
386        self.user_roles.insert(user_id.clone(), new_set).await;
387
388        // Security: Log successful assignment
389        log::info!(
390            "[Ri.Permission] Successfully assigned role '{}' to user '{}'",
391            role_id, user_id
392        );
393
394        Ok(was_added)
395    }
396
397    /// Removes a role from a user.
398    ///
399    /// # Security
400    ///
401    /// - System roles cannot be removed from admin users
402    /// - All role removals are logged for audit purposes
403    ///
404    /// # Parameters
405    /// - `user_id`: The user ID to remove the role from
406    /// - `role_id`: The role ID to remove
407    ///
408    /// # Returns
409    /// `true` if the role was removed, `false` if the user didn't have the role
410    pub async fn remove_role_from_user(&self, user_id: &str, role_id: &str) -> crate::core::RiResult<bool> {
411        // Security: Log all role removals for audit
412        log::info!(
413            "[Ri.Permission] Removing role '{}' from user '{}'",
414            role_id, user_id
415        );
416
417        let user_role_set = self.user_roles.get(user_id).await;
418        
419        match user_role_set {
420            Some(mut set) => {
421                let was_removed = set.remove(role_id);
422                if set.is_empty() {
423                    self.user_roles.remove(user_id).await;
424                } else {
425                    self.user_roles.insert(user_id.to_string(), set).await;
426                }
427
428                if was_removed {
429                    log::info!(
430                        "[Ri.Permission] Successfully removed role '{}' from user '{}'",
431                        role_id, user_id
432                    );
433                }
434
435                Ok(was_removed)
436            }
437            None => Ok(false),
438        }
439    }
440
441    pub async fn get_user_roles(&self, user_id: &str) -> crate::core::RiResult<Vec<RiRole>> {
442        let user_role_set = self.user_roles.get(user_id).await;
443        
444        match user_role_set {
445            Some(role_ids) => {
446                let mut result = Vec::with_capacity(role_ids.len());
447                for role_id in role_ids {
448                    if let Some(role) = self.roles.get(&role_id).await {
449                        result.push(role);
450                    }
451                }
452                Ok(result)
453            }
454            None => Ok(Vec::new()),
455        }
456    }
457
458    pub async fn has_permission(&self, user_id: &str, permission_id: &str) -> crate::core::RiResult<bool> {
459        let user_role_set = self.user_roles.get(user_id).await;
460        
461        if let Some(role_ids) = user_role_set {
462            for role_id in role_ids {
463                if let Some(role) = self.roles.get(&role_id).await {
464                    if role.permissions.contains("*") {
465                        return Ok(true);
466                    }
467                    
468                    if role.permissions.contains(permission_id) {
469                        return Ok(true);
470                    }
471                }
472            }
473        }
474        
475        Ok(false)
476    }
477
478    pub async fn has_any_permission(&self, user_id: &str, permissions: &[String]) -> crate::core::RiResult<bool> {
479        for permission in permissions {
480            if self.has_permission(user_id, permission).await? {
481                return Ok(true);
482            }
483        }
484        Ok(false)
485    }
486
487    pub async fn has_all_permissions(&self, user_id: &str, permissions: &[String]) -> crate::core::RiResult<bool> {
488        for permission in permissions {
489            if !self.has_permission(user_id, permission).await? {
490                return Ok(false);
491            }
492        }
493        Ok(true)
494    }
495
496    pub async fn get_user_permissions(&self, user_id: &str) -> crate::core::RiResult<HashSet<String>> {
497        let user_role_set = self.user_roles.get(user_id).await;
498        
499        let mut permissions = HashSet::new();
500        
501        if let Some(role_ids) = user_role_set {
502            for role_id in role_ids {
503                if let Some(role) = self.roles.get(&role_id).await {
504                    permissions.extend(role.permissions);
505                }
506            }
507        }
508        
509        Ok(permissions)
510    }
511
512    pub async fn delete_permission(&self, permission_id: &str) -> crate::core::RiResult<bool> {
513        Ok(self.permissions.remove(permission_id).await.is_some())
514    }
515
516    pub async fn delete_role(&self, role_id: &str) -> crate::core::RiResult<bool> {
517        let role = self.roles.get(role_id).await;
518        if let Some(r) = role {
519            if r.is_system {
520                return Ok(false);
521            }
522        }
523
524        let was_deleted = self.roles.remove(role_id).await.is_some();
525        
526        if was_deleted {
527            self.user_roles.for_each_mut(|_, role_set| {
528                role_set.remove(role_id);
529            }).await;
530        }
531        
532        Ok(was_deleted)
533    }
534
535    pub async fn list_permissions(&self) -> crate::core::RiResult<Vec<RiPermission>> {
536        Ok(self.permissions.collect_all().await.into_values().collect())
537    }
538
539    pub async fn list_roles(&self) -> crate::core::RiResult<Vec<RiRole>> {
540        Ok(self.roles.collect_all().await.into_values().collect())
541    }
542}
543
544#[cfg(feature = "pyo3")]
545/// Python bindings for the Permission Manager.
546///
547/// This module provides Python interface to Ri RBAC functionality,
548/// enabling Python applications to manage permissions, roles, and user assignments.
549///
550/// ## Supported Operations
551///
552/// - Permission creation and management
553/// - Role creation and management with permission assignments
554/// - User role assignments and removal
555/// - Permission checking for users
556/// - Permission and role listing
557///
558/// ## Python Usage Example
559///
560/// ```python
561/// from ri import RiPermission, RiRole, RiPermissionManager
562///
563/// # Create permission manager
564/// perm_manager = RiPermissionManager()
565///
566/// # Create a permission
567/// permission = RiPermission(
568///     id="read:device",
569///     name="Read Device",
570///     description="Allows reading device information",
571///     resource="device",
572///     action="read",
573/// )
574///
575/// # Create a role
576/// role = RiRole(
577///     id="device_admin",
578///     name="Device Administrator",
579///     description="Manages devices",
580///     permissions=["read:device", "write:device"],
581///     is_system=False,
582/// )
583/// # Note: Async operations require Python 3.7+ with asyncio
584/// ```
585#[pyo3::prelude::pymethods]
586impl RiPermissionManager {
587    #[new]
588    fn py_new() -> PyResult<Self> {
589        Ok(Self::new())
590    }
591    
592    #[pyo3(name = "create_permission")]
593    fn create_permission_impl(&self, permission: RiPermission) -> PyResult<()> {
594        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
595        rt.block_on(async {
596            self.create_permission(permission).await
597                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
598        })
599    }
600    
601    #[pyo3(name = "create_role")]
602    fn create_role_impl(&self, role: RiRole) -> PyResult<()> {
603        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
604        rt.block_on(async {
605            self.create_role(role).await
606                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
607        })
608    }
609    
610    #[pyo3(name = "assign_role_to_user")]
611    fn assign_role_to_user_impl(&self, user_id: String, role_id: String) -> PyResult<bool> {
612        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
613        rt.block_on(async {
614            self.assign_role_to_user(user_id, role_id).await
615                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
616        })
617    }
618    
619    #[pyo3(name = "has_permission")]
620    fn has_permission_impl(&self, user_id: String, permission_id: String) -> PyResult<bool> {
621        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
622        rt.block_on(async {
623            self.has_permission(&user_id, &permission_id).await
624                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
625        })
626    }
627    
628    #[pyo3(name = "get_user_roles")]
629    fn get_user_roles_impl(&self, user_id: String) -> PyResult<Vec<RiRole>> {
630        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
631        rt.block_on(async {
632            self.get_user_roles(&user_id).await
633                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
634        })
635    }
636    
637    #[pyo3(name = "get_user_permissions")]
638    fn get_user_permissions_impl(&self, user_id: String) -> PyResult<Vec<String>> {
639        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
640        rt.block_on(async {
641            self.get_user_permissions(&user_id).await
642                .map(|perms| perms.into_iter().collect())
643                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
644        })
645    }
646    
647    #[pyo3(name = "remove_role_from_user")]
648    fn remove_role_from_user_impl(&self, user_id: String, role_id: String) -> PyResult<bool> {
649        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
650        rt.block_on(async {
651            self.remove_role_from_user(&user_id, &role_id).await
652                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
653        })
654    }
655    
656    #[pyo3(name = "list_roles")]
657    fn list_roles_impl(&self) -> PyResult<Vec<RiRole>> {
658        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
659        rt.block_on(async {
660            self.list_roles().await
661                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
662        })
663    }
664    
665    #[pyo3(name = "list_permissions")]
666    fn list_permissions_impl(&self) -> PyResult<Vec<RiPermission>> {
667        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
668        rt.block_on(async {
669            self.list_permissions().await
670                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
671        })
672    }
673    
674    #[pyo3(name = "delete_role")]
675    fn delete_role_impl(&self, role_id: String) -> PyResult<bool> {
676        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
677        rt.block_on(async {
678            self.delete_role(&role_id).await
679                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
680        })
681    }
682    
683    #[pyo3(name = "delete_permission")]
684    fn delete_permission_impl(&self, permission_id: String) -> PyResult<bool> {
685        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
686        rt.block_on(async {
687            self.delete_permission(&permission_id).await
688                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
689        })
690    }
691    
692    #[pyo3(name = "get_role")]
693    fn get_role_impl(&self, role_id: String) -> PyResult<Option<RiRole>> {
694        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
695        rt.block_on(async {
696            self.get_role(&role_id).await
697                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
698        })
699    }
700    
701    #[pyo3(name = "get_permission")]
702    fn get_permission_impl(&self, permission_id: String) -> PyResult<Option<RiPermission>> {
703        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
704        rt.block_on(async {
705            self.get_permission(&permission_id).await
706                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
707        })
708    }
709    
710    #[pyo3(name = "has_any_permission")]
711    fn has_any_permission_impl(&self, user_id: String, permissions: Vec<String>) -> PyResult<bool> {
712        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
713        rt.block_on(async {
714            self.has_any_permission(&user_id, &permissions).await
715                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
716        })
717    }
718    
719    #[pyo3(name = "has_all_permissions")]
720    fn has_all_permissions_impl(&self, user_id: String, permissions: Vec<String>) -> PyResult<bool> {
721        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
722        rt.block_on(async {
723            self.has_all_permissions(&user_id, &permissions).await
724                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
725        })
726    }
727}