dmsc/auth/
permissions.rs

1//! Copyright © 2025 Wenze Wei. All Rights Reserved.
2//! 
3//! This file is part of DMSC.
4//! The DMSC 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 DMSC.
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 = DMSCPermissionManager::new();
40//! 
41//! // Create a permission
42//! let read_device_perm = DMSCPermission {
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 = DMSCRole::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::{HashMap, HashSet};
71use tokio::sync::RwLock;
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 DMSCPermission {
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 DMSCPermission {
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 DMSCRole {
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 DMSCRole {
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 DMSCRole {
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 `DMSCRole`
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 DMSCPermissionManager {
217    /// Hash map of permissions indexed by permission ID
218    permissions: RwLock<HashMap<String, DMSCPermission>>,
219    /// Hash map of roles indexed by role ID
220    roles: RwLock<HashMap<String, DMSCRole>>,
221    /// Hash map of user role assignments indexed by user ID
222    user_roles: RwLock<HashMap<String, HashSet<String>>>,
223}
224
225impl Default for DMSCPermissionManager {
226    fn default() -> Self {
227        Self::new()
228    }
229}
230
231impl DMSCPermissionManager {
232    /// Creates a new permission manager with default system roles.
233    /// 
234    /// Initializes the manager with two default system roles:
235    /// - `admin`: Has wildcard permission ("*") for all access
236    /// - `user`: Has basic user permissions
237    /// 
238    /// **Performance Note**: This method uses `blocking_write` during initialization
239    /// to set up default roles. For production use, consider using `new_async()` or
240    /// lazy initialization patterns to avoid blocking the async runtime.
241    /// 
242    /// # Returns
243    /// A new instance of `DMSCPermissionManager`
244    pub fn new() -> Self {
245        let mut manager = Self {
246            permissions: RwLock::new(HashMap::new()),
247            roles: RwLock::new(HashMap::new()),
248            user_roles: RwLock::new(HashMap::new()),
249        };
250        
251        // Initialize with default system roles
252        // Note: This uses blocking_write which may block the async runtime
253        manager.initialize_default_roles();
254        manager
255    }
256
257    /// Creates a new permission manager asynchronously with default system roles.
258    /// 
259    /// This is the preferred method for creating a permission manager in async contexts
260    /// as it avoids blocking the runtime during initialization.
261    /// 
262    /// Initializes the manager with two default system roles:
263    /// - `admin`: Has wildcard permission ("*") for all access
264    /// - `user`: Has basic user permissions
265    /// 
266    /// # Returns
267    /// A new instance of `DMSCPermissionManager`
268    pub async fn new_async() -> Self {
269        let manager = Self {
270            permissions: RwLock::new(HashMap::new()),
271            roles: RwLock::new(HashMap::new()),
272            user_roles: RwLock::new(HashMap::new()),
273        };
274        
275        // Initialize with default system roles asynchronously
276        manager.initialize_default_roles_async().await;
277        manager
278    }
279
280    /// Initializes default system roles.
281    /// 
282    /// This method is called during construction to create the default admin
283    /// and user roles. It uses `blocking_write` because it's called from a
284    /// non-async context.
285    /// 
286    /// **Performance Note**: This method is called during initialization and uses
287    /// `blocking_write` to avoid async complexity in the constructor. In production
288    /// scenarios, consider using an async factory pattern or lazy initialization.
289    fn initialize_default_roles(&mut self) {
290        // This would be called in blocking context, so we use blocking_write
291        // Note: In production, consider using an async factory pattern to avoid blocking
292        let mut roles = self.roles.blocking_write();
293        
294        // Admin role - all permissions
295        let admin_permissions: HashSet<String> = vec![
296            "*".to_string(), // Wildcard permission
297        ].into_iter().collect();
298        
299        let admin_role = DMSCRole {
300            id: "admin".to_string(),
301            name: "Administrator".to_string(),
302            description: "Full system access".to_string(),
303            permissions: admin_permissions,
304            is_system: true,
305        };
306        
307        roles.insert("admin".to_string(), admin_role);
308        
309        // User role - basic permissions
310        let user_permissions: HashSet<String> = vec![
311            "read:profile".to_string(),
312            "update:profile".to_string(),
313            "read:own_data".to_string(),
314        ].into_iter().collect();
315        
316        let user_role = DMSCRole {
317            id: "user".to_string(),
318            name: "User".to_string(),
319            description: "Standard user access".to_string(),
320            permissions: user_permissions,
321            is_system: true,
322        };
323        
324        roles.insert("user".to_string(), user_role);
325    }
326
327    /// Initializes default system roles asynchronously.
328    /// 
329    /// This method is the async version of `initialize_default_roles` that avoids
330    /// using `blocking_write`. It should be used when creating the permission manager
331    /// in async contexts.
332    /// 
333    /// **Performance**: This method uses async write locks and is preferred for
334    /// async initialization scenarios.
335    async fn initialize_default_roles_async(&self) {
336        let mut roles = self.roles.write().await;
337        
338        // Admin role - all permissions
339        let admin_permissions: HashSet<String> = vec![
340            "*".to_string(), // Wildcard permission
341        ].into_iter().collect();
342        
343        let admin_role = DMSCRole {
344            id: "admin".to_string(),
345            name: "Administrator".to_string(),
346            description: "Full system access".to_string(),
347            permissions: admin_permissions,
348            is_system: true,
349        };
350        
351        roles.insert("admin".to_string(), admin_role);
352        
353        // User role - basic permissions
354        let user_permissions: HashSet<String> = vec![
355            "read:profile".to_string(),
356            "update:profile".to_string(),
357            "read:own_data".to_string(),
358        ].into_iter().collect();
359        
360        let user_role = DMSCRole {
361            id: "user".to_string(),
362            name: "User".to_string(),
363            description: "Standard user access".to_string(),
364            permissions: user_permissions,
365            is_system: true,
366        };
367        
368        roles.insert("user".to_string(), user_role);
369    }
370
371    /// Creates a new permission.
372    /// 
373    /// # Parameters
374    /// - `permission`: Permission to create
375    /// 
376    /// # Returns
377    /// `Ok(())` if the permission was successfully created
378    pub async fn create_permission(&self, permission: DMSCPermission) -> crate::core::DMSCResult<()> {
379        let mut permissions = self.permissions.write().await;
380        permissions.insert(permission.id.clone(), permission);
381        Ok(())
382    }
383
384    /// Gets a permission by ID.
385    /// 
386    /// # Parameters
387    /// - `permission_id`: Permission ID to retrieve
388    /// 
389    /// # Returns
390    /// `Some(DMSCPermission)` if the permission exists, otherwise `None`
391    pub async fn get_permission(&self, permission_id: &str) -> crate::core::DMSCResult<Option<DMSCPermission>> {
392        let permissions = self.permissions.read().await;
393        Ok(permissions.get(permission_id).cloned())
394    }
395
396    /// Creates a new role.
397    /// 
398    /// # Parameters
399    /// - `role`: Role to create
400    /// 
401    /// # Returns
402    /// `Ok(())` if the role was successfully created
403    pub async fn create_role(&self, role: DMSCRole) -> crate::core::DMSCResult<()> {
404        let mut roles = self.roles.write().await;
405        roles.insert(role.id.clone(), role);
406        Ok(())
407    }
408
409    /// Gets a role by ID.
410    /// 
411    /// # Parameters
412    /// - `role_id`: Role ID to retrieve
413    /// 
414    /// # Returns
415    /// `Some(DMSCRole)` if the role exists, otherwise `None`
416    pub async fn get_role(&self, role_id: &str) -> crate::core::DMSCResult<Option<DMSCRole>> {
417        let roles = self.roles.read().await;
418        Ok(roles.get(role_id).cloned())
419    }
420
421    /// Assigns a role to a user.
422    /// 
423    /// # Parameters
424    /// - `user_id`: User ID to assign the role to
425    /// - `role_id`: Role ID to assign
426    /// 
427    /// # Returns
428    /// `true` if the role was successfully assigned, `false` if the role doesn't exist
429    pub async fn assign_role_to_user(&self, user_id: String, role_id: String) -> crate::core::DMSCResult<bool> {
430        // Check if role exists
431        let roles = self.roles.read().await;
432        if !roles.contains_key(&role_id) {
433            return Ok(false);
434        }
435        drop(roles);
436
437        let mut user_roles = self.user_roles.write().await;
438        let user_role_set = user_roles.entry(user_id).or_insert_with(HashSet::new);
439        let was_added = user_role_set.insert(role_id);
440        Ok(was_added)
441    }
442
443    /// Removes a role from a user.
444    /// 
445    /// # Parameters
446    /// - `user_id`: User ID to remove the role from
447    /// - `role_id`: Role ID to remove
448    /// 
449    /// # Returns
450    /// `true` if the role was successfully removed, `false` if the user didn't have the role
451    pub async fn remove_role_from_user(&self, user_id: &str, role_id: &str) -> crate::core::DMSCResult<bool> {
452        let mut user_roles = self.user_roles.write().await;
453        
454        if let Some(user_role_set) = user_roles.get_mut(user_id) {
455            let was_removed = user_role_set.remove(role_id);
456            if user_role_set.is_empty() {
457                user_roles.remove(user_id);
458            }
459            Ok(was_removed)
460        } else {
461            Ok(false)
462        }
463    }
464
465    /// Gets all roles assigned to a user.
466    /// 
467    /// # Parameters
468    /// - `user_id`: User ID to retrieve roles for
469    /// 
470    /// # Returns
471    /// A vector of `DMSCRole` objects assigned to the user
472    pub async fn get_user_roles(&self, user_id: &str) -> crate::core::DMSCResult<Vec<DMSCRole>> {
473        let user_roles = self.user_roles.read().await;
474        let roles = self.roles.read().await;
475        
476        let mut result = if let Some(user_role_ids) = user_roles.get(user_id) {
477            Vec::with_capacity(user_role_ids.len())
478        } else {
479            Vec::new()
480        };
481        
482        if let Some(user_role_ids) = user_roles.get(user_id) {
483            for role_id in user_role_ids {
484                if let Some(role) = roles.get(role_id) {
485                    result.push(role.clone());
486                }
487            }
488        }
489        
490        Ok(result)
491    }
492
493    /// Checks if a user has a specific permission.
494    /// 
495    /// # Parameters
496    /// - `user_id`: User ID to check
497    /// - `permission_id`: Permission ID to check for
498    /// 
499    /// # Returns
500    /// `true` if the user has the permission, otherwise `false`
501    /// 
502    /// # Notes
503    /// - Users with the wildcard permission ("*") have all permissions
504    /// - Permission checking is done by examining all roles assigned to the user
505    pub async fn has_permission(&self, user_id: &str, permission_id: &str) -> crate::core::DMSCResult<bool> {
506        let user_roles = self.user_roles.read().await;
507        let roles = self.roles.read().await;
508        
509        if let Some(user_role_ids) = user_roles.get(user_id) {
510            for role_id in user_role_ids {
511                if let Some(role) = roles.get(role_id) {
512                    // Check for wildcard permission
513                    if role.permissions.contains("*") {
514                        return Ok(true);
515                    }
516                    
517                    if role.permissions.contains(permission_id) {
518                        return Ok(true);
519                    }
520                }
521            }
522        }
523        
524        Ok(false)
525    }
526
527    /// Checks if a user has any of the specified permissions.
528    /// 
529    /// # Parameters
530    /// - `user_id`: User ID to check
531    /// - `permissions`: List of permission IDs to check for
532    /// 
533    /// # Returns
534    /// `true` if the user has at least one of the permissions, otherwise `false`
535    pub async fn has_any_permission(&self, user_id: &str, permissions: &[String]) -> crate::core::DMSCResult<bool> {
536        for permission in permissions {
537            if self.has_permission(user_id, permission).await? {
538                return Ok(true);
539            }
540        }
541        Ok(false)
542    }
543
544    /// Checks if a user has all of the specified permissions.
545    /// 
546    /// # Parameters
547    /// - `user_id`: User ID to check
548    /// - `permissions`: List of permission IDs to check for
549    /// 
550    /// # Returns
551    /// `true` if the user has all of the permissions, otherwise `false`
552    pub async fn has_all_permissions(&self, user_id: &str, permissions: &[String]) -> crate::core::DMSCResult<bool> {
553        for permission in permissions {
554            if !self.has_permission(user_id, permission).await? {
555                return Ok(false);
556            }
557        }
558        Ok(true)
559    }
560
561    /// Gets all permissions assigned to a user.
562    /// 
563    /// # Parameters
564    /// - `user_id`: User ID to retrieve permissions for
565    /// 
566    /// # Returns
567    /// A set of permission IDs assigned to the user
568    pub async fn get_user_permissions(&self, user_id: &str) -> crate::core::DMSCResult<HashSet<String>> {
569        let user_roles = self.user_roles.read().await;
570        let roles = self.roles.read().await;
571        
572        let mut permissions = HashSet::new();
573        
574        if let Some(user_role_ids) = user_roles.get(user_id) {
575            for role_id in user_role_ids {
576                if let Some(role) = roles.get(role_id) {
577                    permissions.extend(role.permissions.clone());
578                }
579            }
580        }
581        
582        Ok(permissions)
583    }
584
585    /// Deletes a permission.
586    /// 
587    /// # Parameters
588    /// - `permission_id`: Permission ID to delete
589    /// 
590    /// # Returns
591    /// `true` if the permission was successfully deleted, otherwise `false`
592    pub async fn delete_permission(&self, permission_id: &str) -> crate::core::DMSCResult<bool> {
593        let mut permissions = self.permissions.write().await;
594        Ok(permissions.remove(permission_id).is_some())
595    }
596
597    /// Deletes a role.
598    /// 
599    /// # Parameters
600    /// - `role_id`: Role ID to delete
601    /// 
602    /// # Returns
603    /// `true` if the role was successfully deleted, otherwise `false`
604    /// 
605    /// # Notes
606    /// - System roles cannot be deleted
607    /// - If the role is deleted, it is removed from all users
608    pub async fn delete_role(&self, role_id: &str) -> crate::core::DMSCResult<bool> {
609        // Don't delete system roles
610        let roles = self.roles.read().await;
611        if let Some(role) = roles.get(role_id) {
612            if role.is_system {
613                return Ok(false);
614            }
615        }
616        drop(roles);
617
618        let mut roles = self.roles.write().await;
619        let was_deleted = roles.remove(role_id).is_some();
620        
621        if was_deleted {
622            // Remove role from all users
623            let mut user_roles = self.user_roles.write().await;
624            for user_role_set in user_roles.values_mut() {
625                user_role_set.remove(role_id);
626            }
627        }
628        
629        Ok(was_deleted)
630    }
631
632    /// Lists all permissions.
633    /// 
634    /// # Returns
635    /// A vector of all registered permissions
636    pub async fn list_permissions(&self) -> crate::core::DMSCResult<Vec<DMSCPermission>> {
637        let permissions = self.permissions.read().await;
638        Ok(permissions.values().cloned().collect())
639    }
640
641    /// Lists all roles.
642    /// 
643    /// # Returns
644    /// A vector of all registered roles
645    pub async fn list_roles(&self) -> crate::core::DMSCResult<Vec<DMSCRole>> {
646        let roles = self.roles.read().await;
647        Ok(roles.values().cloned().collect())
648    }
649}
650
651#[cfg(feature = "pyo3")]
652/// Python bindings for the Permission Manager.
653///
654/// This module provides Python interface to DMSC RBAC functionality,
655/// enabling Python applications to manage permissions, roles, and user assignments.
656///
657/// ## Supported Operations
658///
659/// - Permission creation and management
660/// - Role creation and management with permission assignments
661/// - User role assignments and removal
662/// - Permission checking for users
663/// - Permission and role listing
664///
665/// ## Python Usage Example
666///
667/// ```python
668/// from dmsc import DMSCPermission, DMSCRole, DMSCPermissionManager
669///
670/// # Create permission manager
671/// perm_manager = DMSCPermissionManager()
672///
673/// # Create a permission
674/// permission = DMSCPermission(
675///     id="read:device",
676///     name="Read Device",
677///     description="Allows reading device information",
678///     resource="device",
679///     action="read",
680/// )
681///
682/// # Create a role
683/// role = DMSCRole(
684///     id="device_admin",
685///     name="Device Administrator",
686///     description="Manages devices",
687///     permissions=["read:device", "write:device"],
688///     is_system=False,
689/// )
690/// # Note: Async operations require Python 3.7+ with asyncio
691/// ```
692#[pyo3::prelude::pymethods]
693impl DMSCPermissionManager {
694    #[new]
695    fn py_new() -> PyResult<Self> {
696        Ok(Self::new())
697    }
698    
699    #[pyo3(name = "create_permission")]
700    fn create_permission_impl(&self, permission: DMSCPermission) -> PyResult<()> {
701        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
702        rt.block_on(async {
703            self.create_permission(permission).await
704                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
705        })
706    }
707    
708    #[pyo3(name = "create_role")]
709    fn create_role_impl(&self, role: DMSCRole) -> PyResult<()> {
710        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
711        rt.block_on(async {
712            self.create_role(role).await
713                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
714        })
715    }
716    
717    #[pyo3(name = "assign_role_to_user")]
718    fn assign_role_to_user_impl(&self, user_id: String, role_id: String) -> PyResult<bool> {
719        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
720        rt.block_on(async {
721            self.assign_role_to_user(user_id, role_id).await
722                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
723        })
724    }
725    
726    #[pyo3(name = "has_permission")]
727    fn has_permission_impl(&self, user_id: String, permission_id: String) -> PyResult<bool> {
728        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
729        rt.block_on(async {
730            self.has_permission(&user_id, &permission_id).await
731                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
732        })
733    }
734    
735    #[pyo3(name = "get_user_roles")]
736    fn get_user_roles_impl(&self, user_id: String) -> PyResult<Vec<DMSCRole>> {
737        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
738        rt.block_on(async {
739            self.get_user_roles(&user_id).await
740                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
741        })
742    }
743    
744    #[pyo3(name = "get_user_permissions")]
745    fn get_user_permissions_impl(&self, user_id: String) -> PyResult<Vec<String>> {
746        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
747        rt.block_on(async {
748            self.get_user_permissions(&user_id).await
749                .map(|perms| perms.into_iter().collect())
750                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
751        })
752    }
753    
754    #[pyo3(name = "remove_role_from_user")]
755    fn remove_role_from_user_impl(&self, user_id: String, role_id: String) -> PyResult<bool> {
756        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
757        rt.block_on(async {
758            self.remove_role_from_user(&user_id, &role_id).await
759                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
760        })
761    }
762    
763    #[pyo3(name = "list_roles")]
764    fn list_roles_impl(&self) -> PyResult<Vec<DMSCRole>> {
765        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
766        rt.block_on(async {
767            self.list_roles().await
768                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
769        })
770    }
771    
772    #[pyo3(name = "list_permissions")]
773    fn list_permissions_impl(&self) -> PyResult<Vec<DMSCPermission>> {
774        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
775        rt.block_on(async {
776            self.list_permissions().await
777                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
778        })
779    }
780    
781    #[pyo3(name = "delete_role")]
782    fn delete_role_impl(&self, role_id: String) -> PyResult<bool> {
783        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
784        rt.block_on(async {
785            self.delete_role(&role_id).await
786                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
787        })
788    }
789    
790    #[pyo3(name = "delete_permission")]
791    fn delete_permission_impl(&self, permission_id: String) -> PyResult<bool> {
792        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
793        rt.block_on(async {
794            self.delete_permission(&permission_id).await
795                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
796        })
797    }
798    
799    #[pyo3(name = "get_role")]
800    fn get_role_impl(&self, role_id: String) -> PyResult<Option<DMSCRole>> {
801        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
802        rt.block_on(async {
803            self.get_role(&role_id).await
804                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
805        })
806    }
807    
808    #[pyo3(name = "get_permission")]
809    fn get_permission_impl(&self, permission_id: String) -> PyResult<Option<DMSCPermission>> {
810        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
811        rt.block_on(async {
812            self.get_permission(&permission_id).await
813                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
814        })
815    }
816    
817    #[pyo3(name = "has_any_permission")]
818    fn has_any_permission_impl(&self, user_id: String, permissions: Vec<String>) -> PyResult<bool> {
819        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
820        rt.block_on(async {
821            self.has_any_permission(&user_id, &permissions).await
822                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
823        })
824    }
825    
826    #[pyo3(name = "has_all_permissions")]
827    fn has_all_permissions_impl(&self, user_id: String, permissions: Vec<String>) -> PyResult<bool> {
828        let rt = tokio::runtime::Runtime::new().map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))?;
829        rt.block_on(async {
830            self.has_all_permissions(&user_id, &permissions).await
831                .map_err(|e| pyo3::exceptions::PyRuntimeError::new_err(e.to_string()))
832        })
833    }
834}