auth_framework/authorization_enhanced/
service.rs

1//! Enhanced Authorization Service using role-system v1.0
2//!
3//! This service provides a unified interface for all authorization operations,
4//! replacing the fragmented authorization systems in AuthFramework.
5
6use crate::errors::{AuthError, Result};
7use role_system::{
8    Permission, Resource, Role, Subject,
9    async_support::{AsyncRoleSystem, AsyncRoleSystemBuilder},
10    storage::{MemoryStorage, Storage},
11};
12use std::collections::HashMap;
13use tracing::{debug, info, warn};
14
15/// Enhanced authorization service providing enterprise-grade RBAC
16pub struct AuthorizationService<S = MemoryStorage>
17where
18    S: Storage + Send + Sync,
19{
20    /// The async role system from role-system v1.0
21    pub role_system: AsyncRoleSystem<S>,
22
23    /// Configuration for the service
24    /// PRODUCTION FIX: Now used for configuration-driven behavior
25    config: AuthorizationConfig,
26}
27
28/// Configuration for the authorization service
29#[derive(Debug, Clone)]
30pub struct AuthorizationConfig {
31    /// Enable audit logging
32    pub enable_audit: bool,
33
34    /// Enable permission caching
35    pub enable_caching: bool,
36
37    /// Cache TTL in seconds
38    pub cache_ttl_seconds: u64,
39
40    /// Maximum role hierarchy depth
41    pub max_hierarchy_depth: usize,
42}
43
44impl Default for AuthorizationConfig {
45    fn default() -> Self {
46        Self {
47            enable_audit: true,
48            enable_caching: true,
49            cache_ttl_seconds: 300, // 5 minutes
50            max_hierarchy_depth: 10,
51        }
52    }
53}
54
55impl AuthorizationService<MemoryStorage> {
56    /// Create a new authorization service with default configuration
57    pub async fn new() -> Result<Self> {
58        Self::with_config(AuthorizationConfig::default()).await
59    }
60
61    /// Create a new authorization service with custom configuration
62    pub async fn with_config(config: AuthorizationConfig) -> Result<Self> {
63        let storage = MemoryStorage::new();
64
65        // Build role system without RoleSystemConfig for now
66        let role_system = AsyncRoleSystemBuilder::new().build_with_storage(storage);
67
68        let service = Self {
69            role_system,
70            config,
71        };
72
73        // Initialize with standard AuthFramework roles
74        service.initialize_authframework_roles().await?;
75
76        info!("AuthorizationService initialized with enhanced RBAC");
77        Ok(service)
78    }
79}
80
81impl<S> AuthorizationService<S>
82where
83    S: Storage + Send + Sync + Default,
84{
85    /// Create authorization service with custom storage
86    pub async fn with_storage(storage: S, config: AuthorizationConfig) -> Result<Self> {
87        // Build role system without RoleSystemConfig for now
88        let role_system = AsyncRoleSystemBuilder::new().build_with_storage(storage);
89
90        let service = Self {
91            role_system,
92            config,
93        };
94
95        service.initialize_authframework_roles().await?;
96
97        info!("AuthorizationService initialized with custom storage");
98        Ok(service)
99    }
100
101    /// Initialize standard AuthFramework roles
102    async fn initialize_authframework_roles(&self) -> Result<()> {
103        info!("Initializing AuthFramework standard roles");
104
105        // Create guest role (minimal permissions)
106        let guest_role = Role::new("guest")
107            .with_description("Unauthenticated user with minimal access")
108            .add_permission(Permission::new("read", "public"));
109
110        // Create user role (authenticated user)
111        let user_role = Role::new("user")
112            .with_description("Authenticated user")
113            .add_permission(Permission::new("read", "profile"))
114            .add_permission(Permission::new("update", "profile:own"))
115            .add_permission(Permission::new("read", "public"));
116
117        // Create moderator role (content moderation)
118        let moderator_role = Role::new("moderator")
119            .with_description("Content moderator")
120            .add_permission(Permission::new("read", "*"))
121            .add_permission(Permission::new("update", "content"))
122            .add_permission(Permission::new("delete", "content"));
123
124        // Create admin role (system administration)
125        let admin_role = Role::new("admin")
126            .with_description("System administrator")
127            .add_permission(Permission::super_admin());
128
129        // Register roles
130        self.role_system
131            .register_role(guest_role)
132            .await
133            .map_err(|e| {
134                AuthError::authorization(format!("Failed to register guest role: {}", e))
135            })?;
136
137        self.role_system
138            .register_role(user_role)
139            .await
140            .map_err(|e| {
141                AuthError::authorization(format!("Failed to register user role: {}", e))
142            })?;
143
144        self.role_system
145            .register_role(moderator_role)
146            .await
147            .map_err(|e| {
148                AuthError::authorization(format!("Failed to register moderator role: {}", e))
149            })?;
150
151        self.role_system
152            .register_role(admin_role)
153            .await
154            .map_err(|e| {
155                AuthError::authorization(format!("Failed to register admin role: {}", e))
156            })?;
157
158        // Set up role hierarchy: admin -> moderator -> user -> guest
159        self.role_system
160            .add_role_inheritance("admin", "moderator")
161            .await
162            .map_err(|e| {
163                AuthError::authorization(format!(
164                    "Failed to set admin->moderator inheritance: {}",
165                    e
166                ))
167            })?;
168
169        self.role_system
170            .add_role_inheritance("moderator", "user")
171            .await
172            .map_err(|e| {
173                AuthError::authorization(format!(
174                    "Failed to set moderator->user inheritance: {}",
175                    e
176                ))
177            })?;
178
179        self.role_system
180            .add_role_inheritance("user", "guest")
181            .await
182            .map_err(|e| {
183                AuthError::authorization(format!("Failed to set user->guest inheritance: {}", e))
184            })?;
185
186        info!("AuthFramework standard roles initialized successfully");
187        Ok(())
188    }
189
190    /// Check if a user has permission to perform an action on a resource
191    pub async fn check_permission(
192        &self,
193        user_id: &str,
194        action: &str,
195        resource_type: &str,
196        context: Option<&HashMap<String, String>>,
197    ) -> Result<bool> {
198        debug!(
199            "Checking permission for user '{}': {}:{}",
200            user_id, action, resource_type
201        );
202
203        let subject = Subject::user(user_id);
204        // Create resource with resource_type as the type and no specific instance
205        let resource = Resource::new("", resource_type); // Empty ID, resource_type as type
206
207        let result = if let Some(context) = context {
208            self.role_system
209                .check_permission_with_context(&subject, action, &resource, context)
210                .await
211        } else {
212            self.role_system
213                .check_permission(&subject, action, &resource)
214                .await
215        };
216
217        // Audit logging based on configuration
218        if self.config.enable_audit {
219            info!(
220                target: "authorization_audit",
221                user_id = user_id,
222                action = action,
223                resource_type = resource_type,
224                permission_granted = result.is_ok() && *result.as_ref().unwrap_or(&false),
225                timestamp = chrono::Utc::now().to_rfc3339(),
226                "Permission check performed"
227            );
228        }
229
230        match result {
231            Ok(granted) => {
232                debug!("Permission check result: {}", granted);
233                Ok(granted)
234            }
235            Err(e) => {
236                warn!("Permission check failed: {}", e);
237                Err(AuthError::authorization(format!(
238                    "Permission check failed: {}",
239                    e
240                )))
241            }
242        }
243    }
244
245    /// Check API endpoint permission
246    pub async fn check_api_permission(
247        &self,
248        user_id: &str,
249        method: &str,
250        endpoint: &str,
251        context: &HashMap<String, String>,
252    ) -> Result<bool> {
253        // Convert HTTP method to action
254        let action = match method.to_uppercase().as_str() {
255            "GET" => "read",
256            "POST" => "create",
257            "PUT" | "PATCH" => "update",
258            "DELETE" => "delete",
259            _ => "access",
260        };
261
262        self.check_permission(user_id, action, endpoint, Some(context))
263            .await
264    }
265
266    /// Assign a role to a user
267    pub async fn assign_role(&self, user_id: &str, role_name: &str) -> Result<()> {
268        debug!("Assigning role '{}' to user '{}'", role_name, user_id);
269
270        let subject = Subject::user(user_id);
271
272        self.role_system
273            .assign_role(&subject, role_name)
274            .await
275            .map_err(|e| AuthError::authorization(format!("Failed to assign role: {}", e)))?;
276
277        info!("Role '{}' assigned to user '{}'", role_name, user_id);
278        Ok(())
279    }
280
281    /// Remove a role from a user
282    pub async fn remove_role(&self, user_id: &str, role_name: &str) -> Result<()> {
283        debug!("Removing role '{}' from user '{}'", role_name, user_id);
284
285        let subject = Subject::user(user_id);
286
287        self.role_system
288            .remove_role(&subject, role_name)
289            .await
290            .map_err(|e| AuthError::authorization(format!("Failed to remove role: {}", e)))?;
291
292        info!("Role '{}' removed from user '{}'", role_name, user_id);
293        Ok(())
294    }
295
296    /// Temporarily elevate a user's role
297    pub async fn elevate_role(
298        &self,
299        user_id: &str,
300        role_name: &str,
301        duration_seconds: Option<u64>,
302    ) -> Result<()> {
303        debug!(
304            "Elevating user '{}' to role '{}' for {:?} seconds",
305            user_id, role_name, duration_seconds
306        );
307
308        let subject = Subject::user(user_id);
309        let duration = duration_seconds.map(std::time::Duration::from_secs);
310
311        self.role_system
312            .elevate_role(&subject, role_name, duration)
313            .await
314            .map_err(|e| AuthError::authorization(format!("Failed to elevate role: {}", e)))?;
315
316        info!(
317            "User '{}' elevated to role '{}' for {:?} seconds",
318            user_id, role_name, duration_seconds
319        );
320        Ok(())
321    }
322
323    /// Get all roles assigned to a user
324    pub async fn get_user_roles(&self, user_id: &str) -> Result<Vec<String>> {
325        let subject = Subject::user(user_id);
326
327        let roles = self
328            .role_system
329            .get_subject_roles(&subject)
330            .await
331            .map_err(|e| AuthError::authorization(format!("Failed to get user roles: {}", e)))?;
332
333        Ok(roles.into_iter().collect())
334    }
335
336    /// Create a new role
337    pub async fn create_role(
338        &self,
339        name: &str,
340        description: &str,
341        permissions: Vec<Permission>,
342        parent_roles: Option<Vec<String>>,
343    ) -> Result<()> {
344        debug!(
345            "Creating role '{}' with {} permissions",
346            name,
347            permissions.len()
348        );
349
350        let mut role = Role::new(name).with_description(description);
351
352        for permission in permissions {
353            role = role.add_permission(permission);
354        }
355
356        self.role_system
357            .register_role(role)
358            .await
359            .map_err(|e| AuthError::authorization(format!("Failed to create role: {}", e)))?;
360
361        // Set up inheritance if specified
362        if let Some(parents) = parent_roles {
363            for parent in parents {
364                self.role_system
365                    .add_role_inheritance(name, &parent)
366                    .await
367                    .map_err(|e| {
368                        AuthError::authorization(format!("Failed to set role inheritance: {}", e))
369                    })?;
370            }
371        }
372
373        info!("Role '{}' created successfully", name);
374        Ok(())
375    }
376
377    /// Get role hierarchy (using new role-system v1.1.1 features)
378    pub async fn get_role_hierarchy(&self, role_id: &str) -> Result<Vec<String>> {
379        // For now, use the working single role approach with parent_role_id
380        if let Ok(Some(role)) = self.role_system.get_role(role_id).await {
381            let mut result = vec![role.id().to_string()];
382            if let Some(parent_id) = role.parent_role_id() {
383                result.push(parent_id.to_string());
384            }
385            Ok(result)
386        } else {
387            Ok(vec![])
388        }
389    }
390
391    /// Test role hierarchy metadata access
392    pub async fn get_role_metadata(&self, role_id: &str) -> Result<String> {
393        if let Ok(Some(role)) = self.role_system.get_role(role_id).await {
394            let depth = role.hierarchy_depth();
395            let is_root = role.is_root_role();
396            let is_leaf = role.is_leaf_role();
397            let children = role.child_role_ids();
398
399            Ok(format!(
400                "Role '{}': depth={}, root={}, leaf={}, children={:?}",
401                role.name(),
402                depth,
403                is_root,
404                is_leaf,
405                children
406            ))
407        } else {
408            Err(AuthError::authorization("Role not found".to_string()))
409        }
410    }
411
412    /// Delete a role
413    pub async fn delete_role(&self, _name: &str) -> Result<()> {
414        // Note: role-system v1.0 doesn't expose delete_role in AsyncRoleSystem
415        // This would need to be implemented by accessing the underlying storage
416        warn!("Role deletion not yet implemented in role-system v1.0");
417        Err(AuthError::authorization(
418            "Role deletion not supported yet".to_string(),
419        ))
420    }
421
422    /// Get role by name
423    pub async fn get_role(&self, name: &str) -> Result<Option<Role>> {
424        self.role_system
425            .get_role(name)
426            .await
427            .map_err(|e| AuthError::authorization(format!("Failed to get role: {}", e)))
428    }
429
430    /// Batch check multiple permissions
431    pub async fn batch_check_permissions(
432        &self,
433        user_id: &str,
434        checks: &[(String, String)], // (action, resource) pairs
435    ) -> Result<Vec<(String, String, bool)>> {
436        let subject = Subject::user(user_id);
437
438        let resource_checks: Vec<(String, Resource)> = checks
439            .iter()
440            .map(|(action, resource)| (action.clone(), Resource::new(resource, "api")))
441            .collect();
442
443        let results = self
444            .role_system
445            .batch_check_permissions(&subject, &resource_checks)
446            .await
447            .map_err(|e| {
448                AuthError::authorization(format!("Batch permission check failed: {}", e))
449            })?;
450
451        Ok(results
452            .into_iter()
453            .map(|(action, resource, granted)| {
454                (
455                    action,
456                    resource.name().unwrap_or("unknown").to_string(),
457                    granted,
458                )
459            })
460            .collect())
461    }
462}
463
464#[cfg(test)]
465mod tests {
466    use super::*;
467
468    #[tokio::test]
469    async fn test_authorization_service_creation() {
470        let service = AuthorizationService::new().await.unwrap();
471
472        // Test that standard roles were created
473        let roles = ["guest", "user", "moderator", "admin"];
474        for role_name in &roles {
475            let role = service.get_role(role_name).await.unwrap();
476            assert!(role.is_some(), "Role '{}' should exist", role_name);
477        }
478    }
479
480    #[tokio::test]
481    async fn test_role_assignment_and_permission_check() {
482        let service = AuthorizationService::new().await.unwrap();
483
484        // Assign user role
485        service.assign_role("test_user", "user").await.unwrap();
486
487        // Check permissions
488        let can_read_profile = service
489            .check_permission("test_user", "read", "profile", None)
490            .await
491            .unwrap();
492        assert!(can_read_profile, "User should have read access to profile");
493
494        let can_admin = service
495            .check_permission("test_user", "admin", "system", None)
496            .await
497            .unwrap();
498        assert!(!can_admin);
499    }
500
501    #[tokio::test]
502    async fn test_role_hierarchy() {
503        let service = AuthorizationService::new().await.unwrap();
504
505        // Assign admin role
506        service.assign_role("admin_user", "admin").await.unwrap();
507
508        // Admin should have user permissions through inheritance
509        let can_read_profile = service
510            .check_permission("admin_user", "read", "profile", None)
511            .await
512            .unwrap();
513        assert!(can_read_profile);
514
515        // Admin should have admin permissions
516        let can_admin = service
517            .check_permission("admin_user", "admin", "system", None)
518            .await
519            .unwrap();
520        assert!(can_admin);
521    }
522}