use super::{PermissionAction, PermissionProvider, PermissionProviderError, RolePolicy, TablePermission};
use dashmap::DashMap;
use std::collections::{HashSet, VecDeque};
use std::sync::Arc;
const MAX_INHERITANCE_DEPTH: usize = 10;
const DEFAULT_INHERITED_ROLES_CACHE_CAPACITY: usize = 1000;
#[derive(Debug, Clone)]
pub struct AdvancedRbacProvider {
roles: Arc<DashMap<String, RolePolicy>>,
role_hierarchy: Arc<DashMap<String, Vec<String>>>,
inherited_roles_cache: Arc<DashMap<String, HashSet<String>>>,
cache_capacity: usize,
}
impl AdvancedRbacProvider {
pub fn new() -> Self {
Self::with_cache_capacity(DEFAULT_INHERITED_ROLES_CACHE_CAPACITY)
}
pub fn with_cache_capacity(cache_capacity: usize) -> Self {
let roles = DashMap::new();
let role_hierarchy = DashMap::new();
let inherited_roles_cache = DashMap::new();
roles.insert(
"admin".to_string(),
RolePolicy {
tables: vec![TablePermission {
name: "*".to_string(),
operations: vec![
PermissionAction::Select,
PermissionAction::Insert,
PermissionAction::Update,
PermissionAction::Delete,
],
}],
},
);
roles.insert(
"readonly".to_string(),
RolePolicy {
tables: vec![TablePermission {
name: "*".to_string(),
operations: vec![PermissionAction::Select],
}],
},
);
roles.insert(
"readwrite".to_string(),
RolePolicy {
tables: vec![TablePermission {
name: "*".to_string(),
operations: vec![
PermissionAction::Select,
PermissionAction::Insert,
PermissionAction::Update,
],
}],
},
);
Self {
roles: Arc::new(roles),
role_hierarchy: Arc::new(role_hierarchy),
inherited_roles_cache: Arc::new(inherited_roles_cache),
cache_capacity,
}
}
pub fn from_config(config: &crate::foundation::config::DbConfig) -> Self {
let cache_capacity = config.cache_config.policy_cache_capacity as usize;
Self::with_cache_capacity(cache_capacity)
}
pub fn add_role(&self, role: String, policy: RolePolicy) {
self.roles.insert(role.clone(), policy);
self.inherited_roles_cache.remove(&role);
}
pub fn add_role_inheritance(&self, child_role: String, parent_roles: Vec<String>) {
self.role_hierarchy.insert(child_role.clone(), parent_roles);
self.inherited_roles_cache.remove(&child_role);
}
pub fn set_role_inheritances(&self, inheritances: Vec<(String, Vec<String>)>) {
for (child, parents) in inheritances {
self.role_hierarchy.insert(child.clone(), parents);
self.inherited_roles_cache.remove(&child);
}
}
pub fn get_inherited_roles(&self, role: &str) -> HashSet<String> {
if let Some(cached) = self.inherited_roles_cache.get(role) {
return cached.clone();
}
let mut inherited = HashSet::new();
let mut queue = VecDeque::new();
queue.push_back((role.to_string(), 0));
while let Some((current, depth)) = queue.pop_front() {
if depth > MAX_INHERITANCE_DEPTH {
continue;
}
if inherited.insert(current.clone()) {
if let Some(parents) = self.role_hierarchy.get(¤t) {
for parent in parents.iter() {
queue.push_back((parent.clone(), depth + 1));
}
}
}
}
if self.inherited_roles_cache.len() < self.cache_capacity {
self.inherited_roles_cache.insert(role.to_string(), inherited.clone());
}
inherited
}
pub fn has_inheritance(&self, role: &str) -> bool {
self.role_hierarchy.contains_key(role)
}
pub fn get_direct_parents(&self, role: &str) -> Option<Vec<String>> {
self.role_hierarchy.get(role).map(|p| p.clone())
}
pub fn remove_inheritance(&self, role: &str) -> bool {
let removed = self.role_hierarchy.remove(role).is_some();
if removed {
self.inherited_roles_cache.remove(role);
}
removed
}
pub fn clear_cache(&self) {
self.inherited_roles_cache.clear();
}
pub fn cache_size(&self) -> usize {
self.inherited_roles_cache.len()
}
fn check_role_access(
&self,
role: &str,
table: &str,
operation: PermissionAction,
) -> Result<bool, PermissionProviderError> {
match self.roles.get(role) {
Some(policy) => {
for table_perm in &policy.tables {
if (table_perm.name == "*" || table_perm.name == table)
&& table_perm.operations.contains(&operation)
{
return Ok(true);
}
}
Ok(false)
}
None => Ok(false), }
}
}
impl Default for AdvancedRbacProvider {
fn default() -> Self {
Self::new()
}
}
impl PermissionProvider for AdvancedRbacProvider {
fn get_role_policy(&self, role: &str) -> Option<RolePolicy> {
self.roles.get(role).map(|p| p.clone())
}
fn check_access(
&self,
role: &str,
table: &str,
operation: PermissionAction,
) -> Result<bool, PermissionProviderError> {
let inherited_roles = self.get_inherited_roles(role);
for inherited_role in inherited_roles.iter() {
match self.check_role_access(inherited_role, table, operation.clone()) {
Ok(true) => return Ok(true),
Ok(false) => continue,
Err(e) => return Err(e),
}
}
Ok(false)
}
fn get_roles(&self) -> Vec<String> {
self.roles.iter().map(|r| r.key().clone()).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_advanced_rbac_basic_check() {
let provider = AdvancedRbacProvider::new();
assert!(
provider
.check_access("admin", "users", PermissionAction::Select)
.unwrap()
);
assert!(
provider
.check_access("admin", "users", PermissionAction::Insert)
.unwrap()
);
assert!(
provider
.check_access("admin", "users", PermissionAction::Update)
.unwrap()
);
assert!(
provider
.check_access("admin", "users", PermissionAction::Delete)
.unwrap()
);
assert!(
provider
.check_access("readonly", "users", PermissionAction::Select)
.unwrap()
);
assert!(
!provider
.check_access("readonly", "users", PermissionAction::Insert)
.unwrap()
);
assert!(
!provider
.check_access("readonly", "users", PermissionAction::Update)
.unwrap()
);
assert!(
!provider
.check_access("readonly", "users", PermissionAction::Delete)
.unwrap()
);
}
#[test]
fn test_role_inheritance() {
let provider = AdvancedRbacProvider::new();
provider.add_role_inheritance("manager".to_string(), vec!["admin".to_string()]);
assert!(
provider
.check_access("manager", "users", PermissionAction::Select)
.unwrap()
);
assert!(
provider
.check_access("manager", "users", PermissionAction::Insert)
.unwrap()
);
assert!(
provider
.check_access("manager", "users", PermissionAction::Delete)
.unwrap()
);
}
#[test]
fn test_multiple_inheritance() {
let provider = AdvancedRbacProvider::new();
provider.add_role_inheritance(
"senior".to_string(),
vec!["readonly".to_string(), "readwrite".to_string()],
);
assert!(
provider
.check_access("senior", "users", PermissionAction::Select)
.unwrap()
);
assert!(
provider
.check_access("senior", "users", PermissionAction::Insert)
.unwrap()
);
assert!(
provider
.check_access("senior", "users", PermissionAction::Update)
.unwrap()
);
assert!(
!provider
.check_access("senior", "users", PermissionAction::Delete)
.unwrap()
);
}
#[test]
fn test_inheritance_chain() {
let provider = AdvancedRbacProvider::new();
provider.add_role_inheritance("junior".to_string(), vec!["mid".to_string()]);
provider.add_role_inheritance("mid".to_string(), vec!["senior".to_string()]);
provider.add_role_inheritance("senior".to_string(), vec!["admin".to_string()]);
assert!(
provider
.check_access("junior", "users", PermissionAction::Select)
.unwrap()
);
assert!(
provider
.check_access("junior", "users", PermissionAction::Insert)
.unwrap()
);
assert!(
provider
.check_access("junior", "users", PermissionAction::Delete)
.unwrap()
);
}
#[test]
fn test_circular_inheritance() {
let provider = AdvancedRbacProvider::new();
provider.add_role_inheritance("role_a".to_string(), vec!["role_b".to_string()]);
provider.add_role_inheritance("role_b".to_string(), vec!["role_a".to_string()]);
provider.add_role(
"role_a".to_string(),
RolePolicy {
tables: vec![TablePermission {
name: "test".to_string(),
operations: vec![PermissionAction::Select],
}],
},
);
let result = provider.check_access("role_a", "test", PermissionAction::Select);
assert!(result.is_ok());
}
#[test]
fn test_get_inherited_roles() {
let provider = AdvancedRbacProvider::new();
provider.add_role_inheritance("child".to_string(), vec!["parent1".to_string(), "parent2".to_string()]);
let inherited = provider.get_inherited_roles("child");
assert!(inherited.iter().any(|role| role == "child"));
assert!(inherited.iter().any(|role| role == "parent1"));
assert!(inherited.iter().any(|role| role == "parent2"));
assert_eq!(inherited.len(), 3);
}
#[test]
fn test_has_inheritance() {
let provider = AdvancedRbacProvider::new();
assert!(!provider.has_inheritance("admin"));
provider.add_role_inheritance("manager".to_string(), vec!["admin".to_string()]);
assert!(provider.has_inheritance("manager"));
}
#[test]
fn test_remove_inheritance() {
let provider = AdvancedRbacProvider::new();
provider.add_role_inheritance("manager".to_string(), vec!["admin".to_string()]);
assert!(provider.has_inheritance("manager"));
let removed = provider.remove_inheritance("manager");
assert!(removed);
assert!(!provider.has_inheritance("manager"));
}
#[test]
fn test_cache_functionality() {
let provider = AdvancedRbacProvider::new();
assert_eq!(provider.cache_size(), 0);
provider
.check_access("admin", "users", PermissionAction::Select)
.unwrap();
assert!(provider.cache_size() > 0);
provider.clear_cache();
assert_eq!(provider.cache_size(), 0);
}
#[test]
fn test_custom_role_addition() {
let provider = AdvancedRbacProvider::new();
provider.add_role(
"custom_role".to_string(),
RolePolicy {
tables: vec![TablePermission {
name: "custom_table".to_string(),
operations: vec![PermissionAction::Select, PermissionAction::Update],
}],
},
);
assert!(
provider
.check_access("custom_role", "custom_table", PermissionAction::Select)
.unwrap()
);
assert!(
provider
.check_access("custom_role", "custom_table", PermissionAction::Update)
.unwrap()
);
assert!(
!provider
.check_access("custom_role", "custom_table", PermissionAction::Insert)
.unwrap()
);
assert!(
!provider
.check_access("custom_role", "custom_table", PermissionAction::Delete)
.unwrap()
);
}
#[test]
fn test_inherit_custom_role() {
let provider = AdvancedRbacProvider::new();
provider.add_role(
"custom_role".to_string(),
RolePolicy {
tables: vec![TablePermission {
name: "custom_table".to_string(),
operations: vec![PermissionAction::Select],
}],
},
);
provider.add_role_inheritance("inherited_role".to_string(), vec!["custom_role".to_string()]);
assert!(
provider
.check_access("inherited_role", "custom_table", PermissionAction::Select)
.unwrap()
);
}
#[test]
fn test_get_roles() {
let provider = AdvancedRbacProvider::new();
let roles = provider.get_roles();
assert!(roles.contains(&"admin".to_string()));
assert!(roles.contains(&"readonly".to_string()));
assert!(roles.contains(&"readwrite".to_string()));
}
#[test]
fn test_batch_inheritances() {
let provider = AdvancedRbacProvider::new();
provider.set_role_inheritances(vec![
("role_a".to_string(), vec!["admin".to_string()]),
("role_b".to_string(), vec!["readonly".to_string()]),
("role_c".to_string(), vec!["role_a".to_string(), "role_b".to_string()]),
]);
assert!(
provider
.check_access("role_c", "users", PermissionAction::Insert)
.unwrap()
); assert!(
provider
.check_access("role_c", "users", PermissionAction::Select)
.unwrap()
); }
#[test]
fn test_undefined_role_denied() {
let provider = AdvancedRbacProvider::new();
assert!(
!provider
.check_access("undefined_role", "users", PermissionAction::Select)
.unwrap()
);
}
#[test]
fn test_wildcard_table_matching() {
let provider = AdvancedRbacProvider::new();
provider.add_role_inheritance("manager".to_string(), vec!["admin".to_string()]);
assert!(
provider
.check_access("manager", "any_table", PermissionAction::Select)
.unwrap()
);
assert!(
provider
.check_access("manager", "another_table", PermissionAction::Insert)
.unwrap()
);
assert!(
provider
.check_access("manager", "third_table", PermissionAction::Delete)
.unwrap()
);
}
#[test]
fn test_inheritance_depth_within_limit() {
let provider = AdvancedRbacProvider::new();
for i in 0..10 {
provider.add_role(
format!("level_{}", i),
RolePolicy {
tables: vec![TablePermission {
name: format!("table_{}", i),
operations: vec![PermissionAction::Select],
}],
},
);
if i == 0 {
provider.add_role_inheritance(format!("level_{}", i), vec!["admin".to_string()]);
} else {
provider.add_role_inheritance(format!("level_{}", i), vec![format!("level_{}", i - 1)]);
}
}
assert!(
provider
.check_access("level_9", "users", PermissionAction::Select)
.unwrap()
);
}
#[test]
fn test_inheritance_depth_exceeds_limit() {
let provider = AdvancedRbacProvider::new();
for i in 0..12 {
provider.add_role(
format!("deep_{}", i),
RolePolicy {
tables: vec![TablePermission {
name: format!("table_{}", i),
operations: vec![PermissionAction::Select],
}],
},
);
if i == 0 {
provider.add_role_inheritance(format!("deep_{}", i), vec!["admin".to_string()]);
} else {
provider.add_role_inheritance(format!("deep_{}", i), vec![format!("deep_{}", i - 1)]);
}
}
let result = provider.check_access("deep_11", "users", PermissionAction::Select);
assert!(result.is_ok());
}
#[test]
fn test_get_inherited_roles_returns_self() {
let provider = AdvancedRbacProvider::new();
let inherited = provider.get_inherited_roles("admin");
assert!(inherited.contains("admin"));
assert_eq!(inherited.len(), 1);
}
#[test]
fn test_circular_inheritance_no_infinite_loop_iterative() {
let provider = AdvancedRbacProvider::new();
provider.add_role_inheritance("a".to_string(), vec!["b".to_string()]);
provider.add_role_inheritance("b".to_string(), vec!["c".to_string()]);
provider.add_role_inheritance("c".to_string(), vec!["d".to_string()]);
provider.add_role_inheritance("d".to_string(), vec!["a".to_string()]);
provider.add_role(
"a".to_string(),
RolePolicy {
tables: vec![TablePermission {
name: "test_table".to_string(),
operations: vec![PermissionAction::Select],
}],
},
);
let result = provider.check_access("a", "test_table", PermissionAction::Select);
assert!(result.is_ok());
assert!(result.unwrap());
}
}