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_engine::{
    PermissionAction, PermissionContext, PermissionDecision, PermissionProvider as PermissionProviderTrait,
    PermissionResource,
};
use dashmap::DashMap;
use std::sync::Arc;

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

/// 角色策略
///
/// 定义角色的权限策略
#[derive(Debug, Clone)]
pub struct RolePolicy {
    /// 表权限列表
    pub tables: Vec<TablePermission>,
}

/// 表权限
///
/// 定义表的访问权限
#[derive(Debug, Clone)]
pub struct TablePermission {
    /// 表名
    pub table_name: String,
    /// 允许的操作列表
    pub actions: Vec<String>,
}

impl RbacProvider {
    /// 创建新的 RBAC 提供者
    ///
    /// 默认包含一个管理员角色,具有所有表的完全访问权限
    pub fn new() -> Self {
        let roles = DashMap::new();
        // 默认管理员角色
        roles.insert(
            "admin".to_string(),
            RolePolicy {
                tables: vec![TablePermission {
                    table_name: "*".to_string(),
                    actions: vec![
                        "SELECT".to_string(),
                        "INSERT".to_string(),
                        "UPDATE".to_string(),
                        "DELETE".to_string(),
                    ],
                }],
            },
        );
        Self { roles: Arc::new(roles) }
    }
}

#[async_trait::async_trait]
impl PermissionProviderTrait for RbacProvider {
    /// 检查权限
    async fn check_permission(&self, context: &PermissionContext) -> PermissionDecision {
        let subject_id = match &context.subject {
            crate::permission_engine::PermissionSubject { id, .. } => id.clone(),
        };

        if let Some(role_policy) = self.roles.get(&subject_id) {
            let resource_name = context.resource.name.clone();
            let action_is_select = matches!(context.action, PermissionAction::Select);

            for table_perm in &role_policy.tables {
                if table_perm.table_name == "*" || table_perm.table_name == resource_name {
                    if table_perm.actions.contains(&"SELECT".to_string()) && action_is_select {
                        return PermissionDecision::Allow;
                    }
                    // 检查其他操作
                    let action_str = context.action.to_string();
                    if table_perm.actions.contains(&action_str) || table_perm.actions.contains(&"*".to_string()) {
                        return PermissionDecision::Allow;
                    }
                }
            }
        }
        PermissionDecision::Deny
    }

    /// 获取主体可访问的资源列表
    async fn get_allowed_resources(&self, subject: &str) -> Vec<PermissionResource> {
        if let Some(role_policy) = self.roles.get(subject) {
            role_policy
                .tables
                .iter()
                .map(|t| PermissionResource::new(&t.table_name))
                .collect()
        } else {
            Vec::new()
        }
    }

    /// 获取主体可执行的操作列表
    async fn get_allowed_actions(&self, subject: &str, resource: &str) -> Vec<PermissionAction> {
        if let Some(role_policy) = self.roles.get(subject) {
            for table_perm in &role_policy.tables {
                if table_perm.table_name == "*" || table_perm.table_name == resource {
                    return table_perm
                        .actions
                        .iter()
                        .filter_map(|op| {
                            match op.to_uppercase().as_str() {
                                "SELECT" => Some(PermissionAction::Select),
                                "INSERT" => Some(PermissionAction::Insert),
                                "UPDATE" => Some(PermissionAction::Update),
                                "DELETE" => Some(PermissionAction::Delete),
                                _ => None, // 不支持自定义操作
                            }
                        })
                        .collect();
                }
            }
        }
        Vec::new()
    }

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

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

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

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

    #[tokio::test]
    async fn test_rbac_provider_check_permission_admin() {
        let provider = RbacProvider::new();
        let context = PermissionContext::new(
            PermissionSubject::role("admin"),
            PermissionResource::new("users"),
            PermissionAction::Select,
        );
        let decision = provider.check_permission(&context).await;
        assert_eq!(decision, PermissionDecision::Allow);
    }

    #[tokio::test]
    async fn test_rbac_provider_check_permission_deny() {
        let provider = RbacProvider::new();
        let context = PermissionContext::new(
            PermissionSubject::role("unknown"),
            PermissionResource::new("users"),
            PermissionAction::Select,
        );
        let decision = provider.check_permission(&context).await;
        assert_eq!(decision, PermissionDecision::Deny);
    }
}