dbnexus 0.1.3

An enterprise-grade database abstraction layer for Rust with built-in permission control and connection pooling
// Copyright (c) 2026 Kirky.X
//
// Licensed under the MIT License
// See LICENSE file in the project root for full license information.

//! 高级 RBAC 权限提供者
//!
//! 提供支持角色继承的基于角色的访问控制实现

use crate::permission::rbac::RbacProvider;
use crate::permission_engine::{
    PermissionAction, PermissionContext, PermissionDecision, PermissionProvider as PermissionProviderTrait,
    PermissionResource,
};
use dashmap::DashMap;
use std::sync::Arc;

/// 高级 RBAC 权限提供者
///
/// 支持角色继承的基于角色的访问控制实现
#[derive(Debug)]
pub struct AdvancedRbacProvider {
    base: RbacProvider,
    role_hierarchy: Arc<DashMap<String, Vec<String>>>,
}

impl AdvancedRbacProvider {
    /// 创建新的高级 RBAC 提供者
    pub fn new() -> Self {
        Self {
            base: RbacProvider::new(),
            role_hierarchy: Arc::new(DashMap::new()),
        }
    }

    /// 添加角色继承关系
    ///
    /// # 参数
    ///
    /// * `child` - 子角色名称
    /// * `parents` - 父角色列表(子角色将继承父角色的所有权限)
    pub fn add_role_inheritance(&self, child: String, parents: Vec<String>) {
        self.role_hierarchy.insert(child, parents);
    }

    /// 递归获取继承的角色列表
    ///
    /// # 参数
    ///
    /// * `role` - 角色名称
    ///
    /// # 返回
    ///
    /// 包含当前角色及所有继承角色的列表
    fn get_inherited_roles(&self, role: &str, roles: &mut Vec<String>) {
        roles.push(role.to_string());
        if let Some(parents) = self.role_hierarchy.get(role) {
            for parent in parents.iter() {
                self.get_inherited_roles(parent, roles);
            }
        }
    }
}

#[async_trait::async_trait]
impl PermissionProviderTrait for AdvancedRbacProvider {
    /// 检查权限
    ///
    /// 首先检查当前角色的权限,如果拒绝,则递归检查继承角色的权限
    async fn check_permission(&self, context: &PermissionContext) -> PermissionDecision {
        let subject_id = match &context.subject {
            crate::permission_engine::PermissionSubject { id, .. } => id.clone(),
        };

        // 检查当前角色
        let decision = self.base.check_permission(context).await;
        if matches!(decision, PermissionDecision::Allow) {
            return decision;
        }

        // 检查继承的角色
        let mut inherited_roles = Vec::new();
        self.get_inherited_roles(&subject_id, &mut inherited_roles);
        for role in inherited_roles {
            let inherited_context = PermissionContext::new(
                crate::permission_engine::PermissionSubject::role(&role),
                context.resource.clone(),
                context.action.clone(),
            );
            let decision = self.base.check_permission(&inherited_context).await;
            if matches!(decision, PermissionDecision::Allow) {
                return decision;
            }
        }

        PermissionDecision::Deny
    }

    /// 获取主体可访问的资源列表
    async fn get_allowed_resources(&self, subject: &str) -> Vec<PermissionResource> {
        self.base.get_allowed_resources(subject).await
    }

    /// 获取主体可执行的操作列表
    async fn get_allowed_actions(&self, subject: &str, resource: &str) -> Vec<PermissionAction> {
        self.base.get_allowed_actions(subject, resource).await
    }

    /// 刷新权限缓存
    async fn refresh(&self) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
        self.base.refresh().await
    }

    /// 获取提供者名称
    fn name(&self) -> &str {
        "advanced-rbac"
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::permission_engine::{PermissionAction, PermissionResource, PermissionSubject};

    #[tokio::test]
    async fn test_advanced_rbac_provider_new() {
        let provider = AdvancedRbacProvider::new();
        assert_eq!(provider.name(), "advanced-rbac");
    }

    #[tokio::test]
    async fn test_advanced_rbac_provider_add_inheritance() {
        let provider = AdvancedRbacProvider::new();
        provider.add_role_inheritance("manager".to_string(), vec!["admin".to_string()]);
        // 添加后应该能够检索到继承关系
        assert!(provider.role_hierarchy.contains_key("manager"));
    }

    #[tokio::test]
    async fn test_advanced_rbac_provider_get_inherited_roles() {
        let provider = AdvancedRbacProvider::new();
        provider.add_role_inheritance("manager".to_string(), vec!["admin".to_string()]);
        let mut roles = Vec::new();
        provider.get_inherited_roles("manager", &mut roles);
        assert!(roles.contains(&"manager".to_string()));
        assert!(roles.contains(&"admin".to_string()));
    }
}