use crate::permission::rbac::RbacProvider;
use crate::permission_engine::{
PermissionAction, PermissionContext, PermissionDecision, PermissionProvider as PermissionProviderTrait,
PermissionResource,
};
use dashmap::DashMap;
use std::sync::Arc;
#[derive(Debug)]
pub struct AdvancedRbacProvider {
base: RbacProvider,
role_hierarchy: Arc<DashMap<String, Vec<String>>>,
}
impl AdvancedRbacProvider {
pub fn new() -> Self {
Self {
base: RbacProvider::new(),
role_hierarchy: Arc::new(DashMap::new()),
}
}
pub fn add_role_inheritance(&self, child: String, parents: Vec<String>) {
self.role_hierarchy.insert(child, parents);
}
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()));
}
}