From f131f7474a51b548f57c7192a5d41e2be048ab91 Mon Sep 17 00:00:00 2001 From: Joey Date: Sun, 18 Aug 2019 00:01:12 +0800 Subject: [PATCH 1/3] use Rc> to store roles to make shared mutability --- src/rbac.rs | 123 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 93 insertions(+), 30 deletions(-) diff --git a/src/rbac.rs b/src/rbac.rs index 6a519ead..38f67da6 100644 --- a/src/rbac.rs +++ b/src/rbac.rs @@ -1,10 +1,13 @@ +use std::cell::RefCell; +use std::rc::Rc; + pub trait RoleManager { fn clone_box(&self) -> Box; fn clear(&mut self); fn add_link(&mut self, name1: &str, name2: &str, domain: Vec<&str>); fn delete_link(&mut self, name1: &str, name2: &str, domain: Vec<&str>); fn has_link(&mut self, name1: &str, name2: &str, domain: Vec<&str>) -> bool; - fn get_roles(&self, name: &str, domain: Vec<&str>) -> Vec<&str>; + fn get_roles(&mut self, name: &str, domain: Option<&str>) -> Vec; fn get_users(&self, name: &str, domain: Vec<&str>) -> Vec<&str>; fn print_roles(&self); } @@ -21,7 +24,7 @@ type MatchingFunc = fn(&str, &str) -> bool; #[derive(Clone)] pub struct DefaultRoleManager { - pub all_roles: HashMap, + pub all_roles: HashMap>>, pub max_hierarchy_level: usize, pub has_pattern: bool, pub matching_func: Option, @@ -37,12 +40,11 @@ impl DefaultRoleManager { }; } - fn create_role(&mut self, name: &str) -> Role { - return self - .all_roles + fn create_role(&mut self, name: &str) -> Rc> { + self.all_roles .entry(name.to_owned()) - .or_insert(Role::new(name.to_owned())) - .clone(); + .or_insert(Rc::new(RefCell::new(Role::new(name.to_owned())))) + .clone() } fn has_role(&self, name: &str) -> bool { @@ -67,13 +69,9 @@ impl RoleManager for DefaultRoleManager { } else if domain.len() > 1 { panic!("error domain length"); } - let mut role1 = self.create_role(name1.as_str()); - let role2 = self.create_role(name2.as_str()); - role1.add_role(role2); - // role1 is updated and should be updated into all_roles - if let Some(old_role) = self.all_roles.get_mut(&role1.name) { - *old_role = role1.clone(); - } + let role1 = self.create_role(&name1); + let role2 = self.create_role(&name2); + role1.borrow_mut().add_role(role2.clone()); } fn delete_link(&mut self, name1: &str, name2: &str, domain: Vec<&str>) { @@ -88,13 +86,9 @@ impl RoleManager for DefaultRoleManager { if !self.has_role(&name1) || !self.has_role(&name2) { panic!("name12 error"); } - let mut role1 = self.create_role(&name1); + let role1 = self.create_role(&name1); let role2 = self.create_role(&name2); - role1.delete_role(role2); - // role1 is updated and should be updated into all_roles - if let Some(old_role) = self.all_roles.get_mut(&role1.name) { - *old_role = role1.clone(); - } + role1.borrow_mut().add_role(role2.clone()); } fn has_link(&mut self, name1: &str, name2: &str, _domain: Vec<&str>) -> bool { @@ -105,11 +99,34 @@ impl RoleManager for DefaultRoleManager { return false; } let role1 = self.create_role(name1); - return role1.has_role(name2, self.max_hierarchy_level); + return role1.borrow().has_role(name2, self.max_hierarchy_level); } - fn get_roles(&self, name: &str, domain: Vec<&str>) -> Vec<&str> { - return vec![]; + fn get_roles(&mut self, name: &str, domain: Option<&str>) -> Vec { + let mut name = name.to_owned(); + if let Some(domain_val) = domain { + name = format!("{}::{}", domain_val.clone(), name); + } + if !self.has_role(&name) { + return vec![]; + } + let role = self.create_role(&name); + + if let Some(domain_val) = domain { + return role + .borrow() + .roles + .iter() + .map(|x| x.borrow().name[domain_val.len() + 2..].to_string()) + .collect(); + } else { + return role + .borrow() + .roles + .iter() + .map(|x| x.borrow().name.clone()) + .collect(); + } } fn get_users(&self, name: &str, domain: Vec<&str>) -> Vec<&str> { @@ -128,7 +145,7 @@ impl RoleManager for DefaultRoleManager { #[derive(Clone, Debug)] pub struct Role { pub name: String, - pub roles: Vec, + pub roles: Vec>>, } impl Role { @@ -139,21 +156,21 @@ impl Role { }; } - pub fn add_role(&mut self, other_role: Role) { + pub fn add_role(&mut self, other_role: Rc>) { for role in self.roles.iter() { - if role.name == other_role.name { + if role.borrow().name == other_role.borrow().name { return; } } - self.roles.push(other_role.clone()); + self.roles.push(other_role); } - fn delete_role(&mut self, other_role: Role) { + fn delete_role(&mut self, other_role: Rc>) { if let Some(pos) = self .roles .iter() .cloned() - .position(|x| x.name == other_role.name) + .position(|x| x.borrow().name == other_role.borrow().name) { self.roles.remove(pos); } @@ -167,10 +184,56 @@ impl Role { return false; } for role in self.roles.iter() { - if role.has_role(name, hierarchy_level - 1) { + if role.borrow().has_role(name, hierarchy_level - 1) { return true; } } return false; } + + fn get_roles(&self) -> Vec { + let mut names = vec![]; + for role in self.roles.iter() { + names.push(role.borrow().name.clone()); + } + return names; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_role() { + let mut rm = DefaultRoleManager::new(3); + rm.add_link("u1", "g1", vec![]); + rm.add_link("u2", "g1", vec![]); + rm.add_link("u3", "g2", vec![]); + rm.add_link("u4", "g2", vec![]); + rm.add_link("u4", "g3", vec![]); + rm.add_link("g1", "g3", vec![]); + + assert_eq!(true, rm.has_link("u1", "g1", vec![])); + assert_eq!(false, rm.has_link("u1", "g2", vec![])); + assert_eq!(true, rm.has_link("u1", "g3", vec![])); + assert_eq!(true, rm.has_link("u2", "g1", vec![])); + assert_eq!(false, rm.has_link("u2", "g2", vec![])); + assert_eq!(true, rm.has_link("u2", "g3", vec![])); + assert_eq!(false, rm.has_link("u3", "g1", vec![])); + assert_eq!(true, rm.has_link("u3", "g2", vec![])); + assert_eq!(false, rm.has_link("u3", "g3", vec![])); + assert_eq!(false, rm.has_link("u4", "g1", vec![])); + assert_eq!(true, rm.has_link("u4", "g2", vec![])); + assert_eq!(true, rm.has_link("u4", "g3", vec![])); + + // test get_roles + assert_eq!(vec!["g1"], rm.get_roles("u1", None)); + assert_eq!(vec!["g1"], rm.get_roles("u2", None)); + assert_eq!(vec!["g2"], rm.get_roles("u3", None)); + assert_eq!(vec!["g2", "g3"], rm.get_roles("u4", None)); + assert_eq!(vec!["g3"], rm.get_roles("g1", None)); + assert_eq!(vec![String::new(); 0], rm.get_roles("g2", None)); + assert_eq!(vec![String::new(); 0], rm.get_roles("g3", None)); + } } From dac60d081e3c36859875a7e76213e8dd5639eadd Mon Sep 17 00:00:00 2001 From: Joey Date: Sun, 18 Aug 2019 09:49:59 +0800 Subject: [PATCH 2/3] implement get_roles and get_users method add more tests --- src/enforcer.rs | 2 +- src/rbac.rs | 203 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 168 insertions(+), 37 deletions(-) diff --git a/src/enforcer.rs b/src/enforcer.rs index b88087b1..10e90827 100644 --- a/src/enforcer.rs +++ b/src/enforcer.rs @@ -30,7 +30,7 @@ impl Clone for Box { pub fn generate_g_function(rm: Box) -> Box { let cb = move |name1: String, name2: String| -> bool { let mut rm = rm.clone(); - return rm.has_link(name1.as_str(), name2.as_str(), vec![]); + return rm.has_link(name1.as_str(), name2.as_str(), None); }; return Box::new(cb); } diff --git a/src/rbac.rs b/src/rbac.rs index 38f67da6..a3002d8d 100644 --- a/src/rbac.rs +++ b/src/rbac.rs @@ -6,9 +6,9 @@ pub trait RoleManager { fn clear(&mut self); fn add_link(&mut self, name1: &str, name2: &str, domain: Vec<&str>); fn delete_link(&mut self, name1: &str, name2: &str, domain: Vec<&str>); - fn has_link(&mut self, name1: &str, name2: &str, domain: Vec<&str>) -> bool; + fn has_link(&mut self, name1: &str, name2: &str, domain: Option<&str>) -> bool; fn get_roles(&mut self, name: &str, domain: Option<&str>) -> Vec; - fn get_users(&self, name: &str, domain: Vec<&str>) -> Vec<&str>; + fn get_users(&self, name: &str, domain: Option<&str>) -> Vec; fn print_roles(&self); } @@ -71,7 +71,7 @@ impl RoleManager for DefaultRoleManager { } let role1 = self.create_role(&name1); let role2 = self.create_role(&name2); - role1.borrow_mut().add_role(role2.clone()); + role1.borrow_mut().add_role(Rc::clone(&role2)); } fn delete_link(&mut self, name1: &str, name2: &str, domain: Vec<&str>) { @@ -88,24 +88,30 @@ impl RoleManager for DefaultRoleManager { } let role1 = self.create_role(&name1); let role2 = self.create_role(&name2); - role1.borrow_mut().add_role(role2.clone()); + role1.borrow_mut().delete_role(Rc::clone(&role2)); } - fn has_link(&mut self, name1: &str, name2: &str, _domain: Vec<&str>) -> bool { + fn has_link(&mut self, name1: &str, name2: &str, domain: Option<&str>) -> bool { + let mut name1 = name1.to_owned(); + let mut name2 = name2.to_owned(); + if let Some(domain_val) = domain { + name1 = format!("{}::{}", domain_val, name1); + name2 = format!("{}::{}", domain_val, name2); + } if name1 == name2 { return true; } - if !self.has_role(name1) || !self.has_role(name2) { + if !self.has_role(&name1) || !self.has_role(&name2) { return false; } - let role1 = self.create_role(name1); - return role1.borrow().has_role(name2, self.max_hierarchy_level); + let role1 = self.create_role(&name1); + return role1.borrow().has_role(&name2, self.max_hierarchy_level); } fn get_roles(&mut self, name: &str, domain: Option<&str>) -> Vec { let mut name = name.to_owned(); if let Some(domain_val) = domain { - name = format!("{}::{}", domain_val.clone(), name); + name = format!("{}::{}", domain_val, name); } if !self.has_role(&name) { return vec![]; @@ -115,22 +121,37 @@ impl RoleManager for DefaultRoleManager { if let Some(domain_val) = domain { return role .borrow() - .roles + .get_roles() .iter() - .map(|x| x.borrow().name[domain_val.len() + 2..].to_string()) + .map(|x| x[domain_val.len() + 2..].to_string()) .collect(); } else { - return role - .borrow() - .roles - .iter() - .map(|x| x.borrow().name.clone()) - .collect(); + return role.borrow().get_roles(); } } - fn get_users(&self, name: &str, domain: Vec<&str>) -> Vec<&str> { - return vec![]; + fn get_users(&self, name: &str, domain: Option<&str>) -> Vec { + let mut name = name.to_owned(); + if let Some(domain_val) = domain { + name = format!("{}::{}", domain_val, name); + } + if !self.has_role(&name) { + return vec![]; + } + + let mut names: Vec = vec![]; + for (_key, role) in self.all_roles.iter() { + if role.borrow().has_direct_role(&name) { + names.push(role.borrow().name.clone()); + } + } + if let Some(domain_val) = domain { + return names + .iter() + .map(|x| x[domain_val.len() + 2..].to_string()) + .collect(); + } + return names; } fn print_roles(&self) { @@ -144,19 +165,19 @@ impl RoleManager for DefaultRoleManager { #[derive(Clone, Debug)] pub struct Role { - pub name: String, - pub roles: Vec>>, + name: String, + roles: Vec>>, } impl Role { - pub fn new(name: String) -> Self { + fn new(name: String) -> Self { return Role { name, roles: vec![], }; } - pub fn add_role(&mut self, other_role: Rc>) { + fn add_role(&mut self, other_role: Rc>) { for role in self.roles.iter() { if role.borrow().name == other_role.borrow().name { return; @@ -169,7 +190,6 @@ impl Role { if let Some(pos) = self .roles .iter() - .cloned() .position(|x| x.borrow().name == other_role.borrow().name) { self.roles.remove(pos); @@ -198,6 +218,15 @@ impl Role { } return names; } + + fn has_direct_role(&self, name: &str) -> bool { + for role in self.roles.iter() { + if role.borrow().name == name { + return true; + } + } + return false; + } } #[cfg(test)] @@ -214,18 +243,18 @@ mod tests { rm.add_link("u4", "g3", vec![]); rm.add_link("g1", "g3", vec![]); - assert_eq!(true, rm.has_link("u1", "g1", vec![])); - assert_eq!(false, rm.has_link("u1", "g2", vec![])); - assert_eq!(true, rm.has_link("u1", "g3", vec![])); - assert_eq!(true, rm.has_link("u2", "g1", vec![])); - assert_eq!(false, rm.has_link("u2", "g2", vec![])); - assert_eq!(true, rm.has_link("u2", "g3", vec![])); - assert_eq!(false, rm.has_link("u3", "g1", vec![])); - assert_eq!(true, rm.has_link("u3", "g2", vec![])); - assert_eq!(false, rm.has_link("u3", "g3", vec![])); - assert_eq!(false, rm.has_link("u4", "g1", vec![])); - assert_eq!(true, rm.has_link("u4", "g2", vec![])); - assert_eq!(true, rm.has_link("u4", "g3", vec![])); + assert_eq!(true, rm.has_link("u1", "g1", None)); + assert_eq!(false, rm.has_link("u1", "g2", None)); + assert_eq!(true, rm.has_link("u1", "g3", None)); + assert_eq!(true, rm.has_link("u2", "g1", None)); + assert_eq!(false, rm.has_link("u2", "g2", None)); + assert_eq!(true, rm.has_link("u2", "g3", None)); + assert_eq!(false, rm.has_link("u3", "g1", None)); + assert_eq!(true, rm.has_link("u3", "g2", None)); + assert_eq!(false, rm.has_link("u3", "g3", None)); + assert_eq!(false, rm.has_link("u4", "g1", None)); + assert_eq!(true, rm.has_link("u4", "g2", None)); + assert_eq!(true, rm.has_link("u4", "g3", None)); // test get_roles assert_eq!(vec!["g1"], rm.get_roles("u1", None)); @@ -235,5 +264,107 @@ mod tests { assert_eq!(vec!["g3"], rm.get_roles("g1", None)); assert_eq!(vec![String::new(); 0], rm.get_roles("g2", None)); assert_eq!(vec![String::new(); 0], rm.get_roles("g3", None)); + + // test delete_link + rm.delete_link("g1", "g3", vec![]); + rm.delete_link("u4", "g2", vec![]); + assert_eq!(true, rm.has_link("u1", "g1", None)); + assert_eq!(false, rm.has_link("u1", "g2", None)); + assert_eq!(false, rm.has_link("u1", "g3", None)); + assert_eq!(true, rm.has_link("u2", "g1", None)); + assert_eq!(false, rm.has_link("u2", "g2", None)); + assert_eq!(false, rm.has_link("u2", "g3", None)); + assert_eq!(false, rm.has_link("u3", "g1", None)); + assert_eq!(true, rm.has_link("u3", "g2", None)); + assert_eq!(false, rm.has_link("u3", "g3", None)); + assert_eq!(false, rm.has_link("u4", "g1", None)); + assert_eq!(false, rm.has_link("u4", "g2", None)); + assert_eq!(true, rm.has_link("u4", "g3", None)); + assert_eq!(vec!["g1"], rm.get_roles("u1", None)); + assert_eq!(vec!["g1"], rm.get_roles("u2", None)); + assert_eq!(vec!["g2"], rm.get_roles("u3", None)); + assert_eq!(vec!["g3"], rm.get_roles("u4", None)); + assert_eq!(vec![String::new(); 0], rm.get_roles("g1", None)); + assert_eq!(vec![String::new(); 0], rm.get_roles("g2", None)); + assert_eq!(vec![String::new(); 0], rm.get_roles("g3", None)); + } + + #[test] + fn test_clear() { + let mut rm = DefaultRoleManager::new(3); + rm.add_link("u1", "g1", vec![]); + rm.add_link("u2", "g1", vec![]); + rm.add_link("u3", "g2", vec![]); + rm.add_link("u4", "g2", vec![]); + rm.add_link("u4", "g3", vec![]); + rm.add_link("g1", "g3", vec![]); + + rm.clear(); + assert_eq!(false, rm.has_link("u1", "g1", None)); + assert_eq!(false, rm.has_link("u1", "g2", None)); + assert_eq!(false, rm.has_link("u1", "g3", None)); + assert_eq!(false, rm.has_link("u2", "g1", None)); + assert_eq!(false, rm.has_link("u2", "g2", None)); + assert_eq!(false, rm.has_link("u2", "g3", None)); + assert_eq!(false, rm.has_link("u3", "g1", None)); + assert_eq!(false, rm.has_link("u3", "g2", None)); + assert_eq!(false, rm.has_link("u3", "g3", None)); + assert_eq!(false, rm.has_link("u4", "g1", None)); + assert_eq!(false, rm.has_link("u4", "g2", None)); + assert_eq!(false, rm.has_link("u4", "g3", None)); + } + + #[test] + fn test_domain_role() { + let mut rm = DefaultRoleManager::new(3); + rm.add_link("u1", "g1", vec!["domain1"]); + rm.add_link("u2", "g1", vec!["domain1"]); + rm.add_link("u3", "admin", vec!["domain2"]); + rm.add_link("u4", "admin", vec!["domain2"]); + rm.add_link("u4", "admin", vec!["domain1"]); + rm.add_link("g1", "admin", vec!["domain1"]); + + assert_eq!(true, rm.has_link("u1", "g1", Some("domain1"))); + assert_eq!(false, rm.has_link("u1", "g1", Some("domain2"))); + assert_eq!(true, rm.has_link("u1", "admin", Some("domain1"))); + assert_eq!(false, rm.has_link("u1", "admin", Some("domain2"))); + + assert_eq!(true, rm.has_link("u2", "g1", Some("domain1"))); + assert_eq!(false, rm.has_link("u2", "g1", Some("domain2"))); + assert_eq!(true, rm.has_link("u2", "admin", Some("domain1"))); + assert_eq!(false, rm.has_link("u2", "admin", Some("domain2"))); + + assert_eq!(false, rm.has_link("u3", "g1", Some("domain1"))); + assert_eq!(false, rm.has_link("u3", "g1", Some("domain2"))); + assert_eq!(false, rm.has_link("u3", "admin", Some("domain1"))); + assert_eq!(true, rm.has_link("u3", "admin", Some("domain2"))); + + assert_eq!(false, rm.has_link("u4", "g1", Some("domain1"))); + assert_eq!(false, rm.has_link("u4", "g1", Some("domain2"))); + assert_eq!(true, rm.has_link("u4", "admin", Some("domain1"))); + assert_eq!(true, rm.has_link("u4", "admin", Some("domain2"))); + + rm.delete_link("g1", "admin", vec!["domain1"]); + rm.delete_link("u4", "admin", vec!["domain2"]); + + assert_eq!(true, rm.has_link("u1", "g1", Some("domain1"))); + assert_eq!(false, rm.has_link("u1", "g1", Some("domain2"))); + assert_eq!(false, rm.has_link("u1", "admin", Some("domain1"))); + assert_eq!(false, rm.has_link("u1", "admin", Some("domain2"))); + + assert_eq!(true, rm.has_link("u2", "g1", Some("domain1"))); + assert_eq!(false, rm.has_link("u2", "g1", Some("domain2"))); + assert_eq!(false, rm.has_link("u2", "admin", Some("domain1"))); + assert_eq!(false, rm.has_link("u2", "admin", Some("domain2"))); + + assert_eq!(false, rm.has_link("u3", "g1", Some("domain1"))); + assert_eq!(false, rm.has_link("u3", "g1", Some("domain2"))); + assert_eq!(false, rm.has_link("u3", "admin", Some("domain1"))); + assert_eq!(true, rm.has_link("u3", "admin", Some("domain2"))); + + assert_eq!(false, rm.has_link("u4", "g1", Some("domain1"))); + assert_eq!(false, rm.has_link("u4", "g1", Some("domain2"))); + assert_eq!(true, rm.has_link("u4", "admin", Some("domain1"))); + assert_eq!(false, rm.has_link("u4", "admin", Some("domain2"))); } } From c92b3e3f1510cb73d8c057b9fd32122beca929f7 Mon Sep 17 00:00:00 2001 From: Joey Date: Sun, 18 Aug 2019 12:20:19 +0800 Subject: [PATCH 3/3] seperate RoleManager and DefaultRoleManager to different files --- src/rbac.rs | 373 +------------------------------ src/rbac/default_role_manager.rs | 353 +++++++++++++++++++++++++++++ src/rbac/role_manager.rs | 16 ++ 3 files changed, 373 insertions(+), 369 deletions(-) create mode 100644 src/rbac/default_role_manager.rs create mode 100644 src/rbac/role_manager.rs diff --git a/src/rbac.rs b/src/rbac.rs index a3002d8d..85caae06 100644 --- a/src/rbac.rs +++ b/src/rbac.rs @@ -1,370 +1,5 @@ -use std::cell::RefCell; -use std::rc::Rc; +mod role_manager; +mod default_role_manager; -pub trait RoleManager { - fn clone_box(&self) -> Box; - fn clear(&mut self); - fn add_link(&mut self, name1: &str, name2: &str, domain: Vec<&str>); - fn delete_link(&mut self, name1: &str, name2: &str, domain: Vec<&str>); - fn has_link(&mut self, name1: &str, name2: &str, domain: Option<&str>) -> bool; - fn get_roles(&mut self, name: &str, domain: Option<&str>) -> Vec; - fn get_users(&self, name: &str, domain: Option<&str>) -> Vec; - fn print_roles(&self); -} - -impl Clone for Box { - fn clone(&self) -> Self { - (*self).clone_box() - } -} - -use std::collections::HashMap; - -type MatchingFunc = fn(&str, &str) -> bool; - -#[derive(Clone)] -pub struct DefaultRoleManager { - pub all_roles: HashMap>>, - pub max_hierarchy_level: usize, - pub has_pattern: bool, - pub matching_func: Option, -} - -impl DefaultRoleManager { - pub fn new(max_hierarchy_level: usize) -> Self { - return DefaultRoleManager { - all_roles: HashMap::new(), - max_hierarchy_level, - has_pattern: false, - matching_func: None, - }; - } - - fn create_role(&mut self, name: &str) -> Rc> { - self.all_roles - .entry(name.to_owned()) - .or_insert(Rc::new(RefCell::new(Role::new(name.to_owned())))) - .clone() - } - - fn has_role(&self, name: &str) -> bool { - if let Some(_role) = self.all_roles.get(name) { - return true; - } - return false; - } -} - -impl RoleManager for DefaultRoleManager { - fn clone_box(&self) -> Box { - Box::new(self.clone()) - } - - fn add_link(&mut self, name1: &str, name2: &str, domain: Vec<&str>) { - let mut name1 = name1.to_owned(); - let mut name2 = name2.to_owned(); - if domain.len() == 1 { - name1 = format!("{}::{}", domain[0], name1); - name2 = format!("{}::{}", domain[0], name2); - } else if domain.len() > 1 { - panic!("error domain length"); - } - let role1 = self.create_role(&name1); - let role2 = self.create_role(&name2); - role1.borrow_mut().add_role(Rc::clone(&role2)); - } - - fn delete_link(&mut self, name1: &str, name2: &str, domain: Vec<&str>) { - let mut name1 = name1.to_owned(); - let mut name2 = name2.to_owned(); - if domain.len() == 1 { - name1 = format!("{}::{}", domain[0], name1); - name2 = format!("{}::{}", domain[0], name2); - } else if domain.len() > 1 { - panic!("error domain length"); - } - if !self.has_role(&name1) || !self.has_role(&name2) { - panic!("name12 error"); - } - let role1 = self.create_role(&name1); - let role2 = self.create_role(&name2); - role1.borrow_mut().delete_role(Rc::clone(&role2)); - } - - fn has_link(&mut self, name1: &str, name2: &str, domain: Option<&str>) -> bool { - let mut name1 = name1.to_owned(); - let mut name2 = name2.to_owned(); - if let Some(domain_val) = domain { - name1 = format!("{}::{}", domain_val, name1); - name2 = format!("{}::{}", domain_val, name2); - } - if name1 == name2 { - return true; - } - if !self.has_role(&name1) || !self.has_role(&name2) { - return false; - } - let role1 = self.create_role(&name1); - return role1.borrow().has_role(&name2, self.max_hierarchy_level); - } - - fn get_roles(&mut self, name: &str, domain: Option<&str>) -> Vec { - let mut name = name.to_owned(); - if let Some(domain_val) = domain { - name = format!("{}::{}", domain_val, name); - } - if !self.has_role(&name) { - return vec![]; - } - let role = self.create_role(&name); - - if let Some(domain_val) = domain { - return role - .borrow() - .get_roles() - .iter() - .map(|x| x[domain_val.len() + 2..].to_string()) - .collect(); - } else { - return role.borrow().get_roles(); - } - } - - fn get_users(&self, name: &str, domain: Option<&str>) -> Vec { - let mut name = name.to_owned(); - if let Some(domain_val) = domain { - name = format!("{}::{}", domain_val, name); - } - if !self.has_role(&name) { - return vec![]; - } - - let mut names: Vec = vec![]; - for (_key, role) in self.all_roles.iter() { - if role.borrow().has_direct_role(&name) { - names.push(role.borrow().name.clone()); - } - } - if let Some(domain_val) = domain { - return names - .iter() - .map(|x| x[domain_val.len() + 2..].to_string()) - .collect(); - } - return names; - } - - fn print_roles(&self) { - println!("current role manager roles: {:?}", self.all_roles.clone()); - } - - fn clear(&mut self) { - self.all_roles = HashMap::new(); - } -} - -#[derive(Clone, Debug)] -pub struct Role { - name: String, - roles: Vec>>, -} - -impl Role { - fn new(name: String) -> Self { - return Role { - name, - roles: vec![], - }; - } - - fn add_role(&mut self, other_role: Rc>) { - for role in self.roles.iter() { - if role.borrow().name == other_role.borrow().name { - return; - } - } - self.roles.push(other_role); - } - - fn delete_role(&mut self, other_role: Rc>) { - if let Some(pos) = self - .roles - .iter() - .position(|x| x.borrow().name == other_role.borrow().name) - { - self.roles.remove(pos); - } - } - - fn has_role(&self, name: &str, hierarchy_level: usize) -> bool { - if self.name == name { - return true; - } - if hierarchy_level <= 0 { - return false; - } - for role in self.roles.iter() { - if role.borrow().has_role(name, hierarchy_level - 1) { - return true; - } - } - return false; - } - - fn get_roles(&self) -> Vec { - let mut names = vec![]; - for role in self.roles.iter() { - names.push(role.borrow().name.clone()); - } - return names; - } - - fn has_direct_role(&self, name: &str) -> bool { - for role in self.roles.iter() { - if role.borrow().name == name { - return true; - } - } - return false; - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_role() { - let mut rm = DefaultRoleManager::new(3); - rm.add_link("u1", "g1", vec![]); - rm.add_link("u2", "g1", vec![]); - rm.add_link("u3", "g2", vec![]); - rm.add_link("u4", "g2", vec![]); - rm.add_link("u4", "g3", vec![]); - rm.add_link("g1", "g3", vec![]); - - assert_eq!(true, rm.has_link("u1", "g1", None)); - assert_eq!(false, rm.has_link("u1", "g2", None)); - assert_eq!(true, rm.has_link("u1", "g3", None)); - assert_eq!(true, rm.has_link("u2", "g1", None)); - assert_eq!(false, rm.has_link("u2", "g2", None)); - assert_eq!(true, rm.has_link("u2", "g3", None)); - assert_eq!(false, rm.has_link("u3", "g1", None)); - assert_eq!(true, rm.has_link("u3", "g2", None)); - assert_eq!(false, rm.has_link("u3", "g3", None)); - assert_eq!(false, rm.has_link("u4", "g1", None)); - assert_eq!(true, rm.has_link("u4", "g2", None)); - assert_eq!(true, rm.has_link("u4", "g3", None)); - - // test get_roles - assert_eq!(vec!["g1"], rm.get_roles("u1", None)); - assert_eq!(vec!["g1"], rm.get_roles("u2", None)); - assert_eq!(vec!["g2"], rm.get_roles("u3", None)); - assert_eq!(vec!["g2", "g3"], rm.get_roles("u4", None)); - assert_eq!(vec!["g3"], rm.get_roles("g1", None)); - assert_eq!(vec![String::new(); 0], rm.get_roles("g2", None)); - assert_eq!(vec![String::new(); 0], rm.get_roles("g3", None)); - - // test delete_link - rm.delete_link("g1", "g3", vec![]); - rm.delete_link("u4", "g2", vec![]); - assert_eq!(true, rm.has_link("u1", "g1", None)); - assert_eq!(false, rm.has_link("u1", "g2", None)); - assert_eq!(false, rm.has_link("u1", "g3", None)); - assert_eq!(true, rm.has_link("u2", "g1", None)); - assert_eq!(false, rm.has_link("u2", "g2", None)); - assert_eq!(false, rm.has_link("u2", "g3", None)); - assert_eq!(false, rm.has_link("u3", "g1", None)); - assert_eq!(true, rm.has_link("u3", "g2", None)); - assert_eq!(false, rm.has_link("u3", "g3", None)); - assert_eq!(false, rm.has_link("u4", "g1", None)); - assert_eq!(false, rm.has_link("u4", "g2", None)); - assert_eq!(true, rm.has_link("u4", "g3", None)); - assert_eq!(vec!["g1"], rm.get_roles("u1", None)); - assert_eq!(vec!["g1"], rm.get_roles("u2", None)); - assert_eq!(vec!["g2"], rm.get_roles("u3", None)); - assert_eq!(vec!["g3"], rm.get_roles("u4", None)); - assert_eq!(vec![String::new(); 0], rm.get_roles("g1", None)); - assert_eq!(vec![String::new(); 0], rm.get_roles("g2", None)); - assert_eq!(vec![String::new(); 0], rm.get_roles("g3", None)); - } - - #[test] - fn test_clear() { - let mut rm = DefaultRoleManager::new(3); - rm.add_link("u1", "g1", vec![]); - rm.add_link("u2", "g1", vec![]); - rm.add_link("u3", "g2", vec![]); - rm.add_link("u4", "g2", vec![]); - rm.add_link("u4", "g3", vec![]); - rm.add_link("g1", "g3", vec![]); - - rm.clear(); - assert_eq!(false, rm.has_link("u1", "g1", None)); - assert_eq!(false, rm.has_link("u1", "g2", None)); - assert_eq!(false, rm.has_link("u1", "g3", None)); - assert_eq!(false, rm.has_link("u2", "g1", None)); - assert_eq!(false, rm.has_link("u2", "g2", None)); - assert_eq!(false, rm.has_link("u2", "g3", None)); - assert_eq!(false, rm.has_link("u3", "g1", None)); - assert_eq!(false, rm.has_link("u3", "g2", None)); - assert_eq!(false, rm.has_link("u3", "g3", None)); - assert_eq!(false, rm.has_link("u4", "g1", None)); - assert_eq!(false, rm.has_link("u4", "g2", None)); - assert_eq!(false, rm.has_link("u4", "g3", None)); - } - - #[test] - fn test_domain_role() { - let mut rm = DefaultRoleManager::new(3); - rm.add_link("u1", "g1", vec!["domain1"]); - rm.add_link("u2", "g1", vec!["domain1"]); - rm.add_link("u3", "admin", vec!["domain2"]); - rm.add_link("u4", "admin", vec!["domain2"]); - rm.add_link("u4", "admin", vec!["domain1"]); - rm.add_link("g1", "admin", vec!["domain1"]); - - assert_eq!(true, rm.has_link("u1", "g1", Some("domain1"))); - assert_eq!(false, rm.has_link("u1", "g1", Some("domain2"))); - assert_eq!(true, rm.has_link("u1", "admin", Some("domain1"))); - assert_eq!(false, rm.has_link("u1", "admin", Some("domain2"))); - - assert_eq!(true, rm.has_link("u2", "g1", Some("domain1"))); - assert_eq!(false, rm.has_link("u2", "g1", Some("domain2"))); - assert_eq!(true, rm.has_link("u2", "admin", Some("domain1"))); - assert_eq!(false, rm.has_link("u2", "admin", Some("domain2"))); - - assert_eq!(false, rm.has_link("u3", "g1", Some("domain1"))); - assert_eq!(false, rm.has_link("u3", "g1", Some("domain2"))); - assert_eq!(false, rm.has_link("u3", "admin", Some("domain1"))); - assert_eq!(true, rm.has_link("u3", "admin", Some("domain2"))); - - assert_eq!(false, rm.has_link("u4", "g1", Some("domain1"))); - assert_eq!(false, rm.has_link("u4", "g1", Some("domain2"))); - assert_eq!(true, rm.has_link("u4", "admin", Some("domain1"))); - assert_eq!(true, rm.has_link("u4", "admin", Some("domain2"))); - - rm.delete_link("g1", "admin", vec!["domain1"]); - rm.delete_link("u4", "admin", vec!["domain2"]); - - assert_eq!(true, rm.has_link("u1", "g1", Some("domain1"))); - assert_eq!(false, rm.has_link("u1", "g1", Some("domain2"))); - assert_eq!(false, rm.has_link("u1", "admin", Some("domain1"))); - assert_eq!(false, rm.has_link("u1", "admin", Some("domain2"))); - - assert_eq!(true, rm.has_link("u2", "g1", Some("domain1"))); - assert_eq!(false, rm.has_link("u2", "g1", Some("domain2"))); - assert_eq!(false, rm.has_link("u2", "admin", Some("domain1"))); - assert_eq!(false, rm.has_link("u2", "admin", Some("domain2"))); - - assert_eq!(false, rm.has_link("u3", "g1", Some("domain1"))); - assert_eq!(false, rm.has_link("u3", "g1", Some("domain2"))); - assert_eq!(false, rm.has_link("u3", "admin", Some("domain1"))); - assert_eq!(true, rm.has_link("u3", "admin", Some("domain2"))); - - assert_eq!(false, rm.has_link("u4", "g1", Some("domain1"))); - assert_eq!(false, rm.has_link("u4", "g1", Some("domain2"))); - assert_eq!(true, rm.has_link("u4", "admin", Some("domain1"))); - assert_eq!(false, rm.has_link("u4", "admin", Some("domain2"))); - } -} +pub use role_manager::RoleManager; +pub use default_role_manager::DefaultRoleManager; diff --git a/src/rbac/default_role_manager.rs b/src/rbac/default_role_manager.rs new file mode 100644 index 00000000..38203518 --- /dev/null +++ b/src/rbac/default_role_manager.rs @@ -0,0 +1,353 @@ +use std::cell::RefCell; +use std::rc::Rc; +use std::collections::HashMap; +use crate::rbac::RoleManager; + +type MatchingFunc = fn(&str, &str) -> bool; + +#[derive(Clone)] +pub struct DefaultRoleManager { + pub all_roles: HashMap>>, + pub max_hierarchy_level: usize, + pub has_pattern: bool, + pub matching_func: Option, +} + +impl DefaultRoleManager { + pub fn new(max_hierarchy_level: usize) -> Self { + return DefaultRoleManager { + all_roles: HashMap::new(), + max_hierarchy_level, + has_pattern: false, + matching_func: None, + }; + } + + fn create_role(&mut self, name: &str) -> Rc> { + self.all_roles + .entry(name.to_owned()) + .or_insert(Rc::new(RefCell::new(Role::new(name.to_owned())))) + .clone() + } + + fn has_role(&self, name: &str) -> bool { + if let Some(_role) = self.all_roles.get(name) { + return true; + } + return false; + } +} + +impl RoleManager for DefaultRoleManager { + fn clone_box(&self) -> Box { + Box::new(self.clone()) + } + + fn add_link(&mut self, name1: &str, name2: &str, domain: Vec<&str>) { + let mut name1 = name1.to_owned(); + let mut name2 = name2.to_owned(); + if domain.len() == 1 { + name1 = format!("{}::{}", domain[0], name1); + name2 = format!("{}::{}", domain[0], name2); + } else if domain.len() > 1 { + panic!("error domain length"); + } + let role1 = self.create_role(&name1); + let role2 = self.create_role(&name2); + role1.borrow_mut().add_role(Rc::clone(&role2)); + } + + fn delete_link(&mut self, name1: &str, name2: &str, domain: Vec<&str>) { + let mut name1 = name1.to_owned(); + let mut name2 = name2.to_owned(); + if domain.len() == 1 { + name1 = format!("{}::{}", domain[0], name1); + name2 = format!("{}::{}", domain[0], name2); + } else if domain.len() > 1 { + panic!("error domain length"); + } + if !self.has_role(&name1) || !self.has_role(&name2) { + panic!("name12 error"); + } + let role1 = self.create_role(&name1); + let role2 = self.create_role(&name2); + role1.borrow_mut().delete_role(Rc::clone(&role2)); + } + + fn has_link(&mut self, name1: &str, name2: &str, domain: Option<&str>) -> bool { + let mut name1 = name1.to_owned(); + let mut name2 = name2.to_owned(); + if let Some(domain_val) = domain { + name1 = format!("{}::{}", domain_val, name1); + name2 = format!("{}::{}", domain_val, name2); + } + if name1 == name2 { + return true; + } + if !self.has_role(&name1) || !self.has_role(&name2) { + return false; + } + let role1 = self.create_role(&name1); + return role1.borrow().has_role(&name2, self.max_hierarchy_level); + } + + fn get_roles(&mut self, name: &str, domain: Option<&str>) -> Vec { + let mut name = name.to_owned(); + if let Some(domain_val) = domain { + name = format!("{}::{}", domain_val, name); + } + if !self.has_role(&name) { + return vec![]; + } + let role = self.create_role(&name); + + if let Some(domain_val) = domain { + return role + .borrow() + .get_roles() + .iter() + .map(|x| x[domain_val.len() + 2..].to_string()) + .collect(); + } else { + return role.borrow().get_roles(); + } + } + + fn get_users(&self, name: &str, domain: Option<&str>) -> Vec { + let mut name = name.to_owned(); + if let Some(domain_val) = domain { + name = format!("{}::{}", domain_val, name); + } + if !self.has_role(&name) { + return vec![]; + } + + let mut names: Vec = vec![]; + for (_key, role) in self.all_roles.iter() { + if role.borrow().has_direct_role(&name) { + names.push(role.borrow().name.clone()); + } + } + if let Some(domain_val) = domain { + return names + .iter() + .map(|x| x[domain_val.len() + 2..].to_string()) + .collect(); + } + return names; + } + + fn print_roles(&self) { + println!("current role manager roles: {:?}", self.all_roles.clone()); + } + + fn clear(&mut self) { + self.all_roles = HashMap::new(); + } +} + +#[derive(Clone, Debug)] +pub struct Role { + name: String, + roles: Vec>>, +} + +impl Role { + fn new(name: String) -> Self { + return Role { + name, + roles: vec![], + }; + } + + fn add_role(&mut self, other_role: Rc>) { + for role in self.roles.iter() { + if role.borrow().name == other_role.borrow().name { + return; + } + } + self.roles.push(other_role); + } + + fn delete_role(&mut self, other_role: Rc>) { + if let Some(pos) = self + .roles + .iter() + .position(|x| x.borrow().name == other_role.borrow().name) + { + self.roles.remove(pos); + } + } + + fn has_role(&self, name: &str, hierarchy_level: usize) -> bool { + if self.name == name { + return true; + } + if hierarchy_level <= 0 { + return false; + } + for role in self.roles.iter() { + if role.borrow().has_role(name, hierarchy_level - 1) { + return true; + } + } + return false; + } + + fn get_roles(&self) -> Vec { + let mut names = vec![]; + for role in self.roles.iter() { + names.push(role.borrow().name.clone()); + } + return names; + } + + fn has_direct_role(&self, name: &str) -> bool { + for role in self.roles.iter() { + if role.borrow().name == name { + return true; + } + } + return false; + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_role() { + let mut rm = DefaultRoleManager::new(3); + rm.add_link("u1", "g1", vec![]); + rm.add_link("u2", "g1", vec![]); + rm.add_link("u3", "g2", vec![]); + rm.add_link("u4", "g2", vec![]); + rm.add_link("u4", "g3", vec![]); + rm.add_link("g1", "g3", vec![]); + + assert_eq!(true, rm.has_link("u1", "g1", None)); + assert_eq!(false, rm.has_link("u1", "g2", None)); + assert_eq!(true, rm.has_link("u1", "g3", None)); + assert_eq!(true, rm.has_link("u2", "g1", None)); + assert_eq!(false, rm.has_link("u2", "g2", None)); + assert_eq!(true, rm.has_link("u2", "g3", None)); + assert_eq!(false, rm.has_link("u3", "g1", None)); + assert_eq!(true, rm.has_link("u3", "g2", None)); + assert_eq!(false, rm.has_link("u3", "g3", None)); + assert_eq!(false, rm.has_link("u4", "g1", None)); + assert_eq!(true, rm.has_link("u4", "g2", None)); + assert_eq!(true, rm.has_link("u4", "g3", None)); + + // test get_roles + assert_eq!(vec!["g1"], rm.get_roles("u1", None)); + assert_eq!(vec!["g1"], rm.get_roles("u2", None)); + assert_eq!(vec!["g2"], rm.get_roles("u3", None)); + assert_eq!(vec!["g2", "g3"], rm.get_roles("u4", None)); + assert_eq!(vec!["g3"], rm.get_roles("g1", None)); + assert_eq!(vec![String::new(); 0], rm.get_roles("g2", None)); + assert_eq!(vec![String::new(); 0], rm.get_roles("g3", None)); + + // test delete_link + rm.delete_link("g1", "g3", vec![]); + rm.delete_link("u4", "g2", vec![]); + assert_eq!(true, rm.has_link("u1", "g1", None)); + assert_eq!(false, rm.has_link("u1", "g2", None)); + assert_eq!(false, rm.has_link("u1", "g3", None)); + assert_eq!(true, rm.has_link("u2", "g1", None)); + assert_eq!(false, rm.has_link("u2", "g2", None)); + assert_eq!(false, rm.has_link("u2", "g3", None)); + assert_eq!(false, rm.has_link("u3", "g1", None)); + assert_eq!(true, rm.has_link("u3", "g2", None)); + assert_eq!(false, rm.has_link("u3", "g3", None)); + assert_eq!(false, rm.has_link("u4", "g1", None)); + assert_eq!(false, rm.has_link("u4", "g2", None)); + assert_eq!(true, rm.has_link("u4", "g3", None)); + assert_eq!(vec!["g1"], rm.get_roles("u1", None)); + assert_eq!(vec!["g1"], rm.get_roles("u2", None)); + assert_eq!(vec!["g2"], rm.get_roles("u3", None)); + assert_eq!(vec!["g3"], rm.get_roles("u4", None)); + assert_eq!(vec![String::new(); 0], rm.get_roles("g1", None)); + assert_eq!(vec![String::new(); 0], rm.get_roles("g2", None)); + assert_eq!(vec![String::new(); 0], rm.get_roles("g3", None)); + } + + #[test] + fn test_clear() { + let mut rm = DefaultRoleManager::new(3); + rm.add_link("u1", "g1", vec![]); + rm.add_link("u2", "g1", vec![]); + rm.add_link("u3", "g2", vec![]); + rm.add_link("u4", "g2", vec![]); + rm.add_link("u4", "g3", vec![]); + rm.add_link("g1", "g3", vec![]); + + rm.clear(); + assert_eq!(false, rm.has_link("u1", "g1", None)); + assert_eq!(false, rm.has_link("u1", "g2", None)); + assert_eq!(false, rm.has_link("u1", "g3", None)); + assert_eq!(false, rm.has_link("u2", "g1", None)); + assert_eq!(false, rm.has_link("u2", "g2", None)); + assert_eq!(false, rm.has_link("u2", "g3", None)); + assert_eq!(false, rm.has_link("u3", "g1", None)); + assert_eq!(false, rm.has_link("u3", "g2", None)); + assert_eq!(false, rm.has_link("u3", "g3", None)); + assert_eq!(false, rm.has_link("u4", "g1", None)); + assert_eq!(false, rm.has_link("u4", "g2", None)); + assert_eq!(false, rm.has_link("u4", "g3", None)); + } + + #[test] + fn test_domain_role() { + let mut rm = DefaultRoleManager::new(3); + rm.add_link("u1", "g1", vec!["domain1"]); + rm.add_link("u2", "g1", vec!["domain1"]); + rm.add_link("u3", "admin", vec!["domain2"]); + rm.add_link("u4", "admin", vec!["domain2"]); + rm.add_link("u4", "admin", vec!["domain1"]); + rm.add_link("g1", "admin", vec!["domain1"]); + + assert_eq!(true, rm.has_link("u1", "g1", Some("domain1"))); + assert_eq!(false, rm.has_link("u1", "g1", Some("domain2"))); + assert_eq!(true, rm.has_link("u1", "admin", Some("domain1"))); + assert_eq!(false, rm.has_link("u1", "admin", Some("domain2"))); + + assert_eq!(true, rm.has_link("u2", "g1", Some("domain1"))); + assert_eq!(false, rm.has_link("u2", "g1", Some("domain2"))); + assert_eq!(true, rm.has_link("u2", "admin", Some("domain1"))); + assert_eq!(false, rm.has_link("u2", "admin", Some("domain2"))); + + assert_eq!(false, rm.has_link("u3", "g1", Some("domain1"))); + assert_eq!(false, rm.has_link("u3", "g1", Some("domain2"))); + assert_eq!(false, rm.has_link("u3", "admin", Some("domain1"))); + assert_eq!(true, rm.has_link("u3", "admin", Some("domain2"))); + + assert_eq!(false, rm.has_link("u4", "g1", Some("domain1"))); + assert_eq!(false, rm.has_link("u4", "g1", Some("domain2"))); + assert_eq!(true, rm.has_link("u4", "admin", Some("domain1"))); + assert_eq!(true, rm.has_link("u4", "admin", Some("domain2"))); + + rm.delete_link("g1", "admin", vec!["domain1"]); + rm.delete_link("u4", "admin", vec!["domain2"]); + + assert_eq!(true, rm.has_link("u1", "g1", Some("domain1"))); + assert_eq!(false, rm.has_link("u1", "g1", Some("domain2"))); + assert_eq!(false, rm.has_link("u1", "admin", Some("domain1"))); + assert_eq!(false, rm.has_link("u1", "admin", Some("domain2"))); + + assert_eq!(true, rm.has_link("u2", "g1", Some("domain1"))); + assert_eq!(false, rm.has_link("u2", "g1", Some("domain2"))); + assert_eq!(false, rm.has_link("u2", "admin", Some("domain1"))); + assert_eq!(false, rm.has_link("u2", "admin", Some("domain2"))); + + assert_eq!(false, rm.has_link("u3", "g1", Some("domain1"))); + assert_eq!(false, rm.has_link("u3", "g1", Some("domain2"))); + assert_eq!(false, rm.has_link("u3", "admin", Some("domain1"))); + assert_eq!(true, rm.has_link("u3", "admin", Some("domain2"))); + + assert_eq!(false, rm.has_link("u4", "g1", Some("domain1"))); + assert_eq!(false, rm.has_link("u4", "g1", Some("domain2"))); + assert_eq!(true, rm.has_link("u4", "admin", Some("domain1"))); + assert_eq!(false, rm.has_link("u4", "admin", Some("domain2"))); + } +} diff --git a/src/rbac/role_manager.rs b/src/rbac/role_manager.rs new file mode 100644 index 00000000..73798f18 --- /dev/null +++ b/src/rbac/role_manager.rs @@ -0,0 +1,16 @@ +pub trait RoleManager { + fn clone_box(&self) -> Box; + fn clear(&mut self); + fn add_link(&mut self, name1: &str, name2: &str, domain: Vec<&str>); + fn delete_link(&mut self, name1: &str, name2: &str, domain: Vec<&str>); + fn has_link(&mut self, name1: &str, name2: &str, domain: Option<&str>) -> bool; + fn get_roles(&mut self, name: &str, domain: Option<&str>) -> Vec; + fn get_users(&self, name: &str, domain: Option<&str>) -> Vec; + fn print_roles(&self); +} + +impl Clone for Box { + fn clone(&self) -> Self { + (*self).clone_box() + } +}