1use crate::{
2 config::Config,
3 error::ModelError,
4 model::{Assertion, AssertionMap, Model},
5 rbac::RoleManager,
6 util::*,
7 Result,
8};
9
10#[cfg(feature = "incremental")]
11use crate::emitter::EventData;
12
13use hashlink::{LinkedHashMap, LinkedHashSet};
14use parking_lot::RwLock;
15
16#[cfg(all(feature = "runtime-async-std", not(target_arch = "wasm32")))]
17use async_std::path::Path as ioPath;
18
19#[cfg(feature = "runtime-tokio")]
20use std::path::Path as ioPath;
21
22use rhai::{Engine, AST};
23use std::{collections::HashMap, sync::Arc};
24
25#[derive(Clone, Default)]
26pub struct DefaultModel {
27 pub(crate) model: HashMap<String, AssertionMap>,
28 compiled_matchers: HashMap<String, AST>,
31}
32
33impl DefaultModel {
34 pub fn compile_matchers(&mut self, engine: &Engine) -> Result<()> {
37 self.compiled_matchers.clear();
38
39 if let Some(assertions) = self.model.get("m") {
41 for (key, assertion) in assertions {
42 let compiled = engine
43 .compile_expression(crate::util::escape_eval(
44 &assertion.value,
45 ))
46 .map_err(|e| {
47 crate::error::Error::ModelError(
48 crate::error::ModelError::M(format!(
49 "Failed to compile matcher '{}': {}",
50 key, e
51 )),
52 )
53 })?;
54
55 self.compiled_matchers.insert(key.clone(), compiled);
57 }
58 }
59 Ok(())
60 }
61
62 #[inline]
64 pub fn get_compiled_matcher(&self, key: &str) -> Option<&AST> {
65 self.compiled_matchers.get(key)
66 }
67 #[cfg(not(target_arch = "wasm32"))]
68 pub async fn from_file<P: AsRef<ioPath>>(p: P) -> Result<DefaultModel> {
69 let cfg = Config::from_file(p).await?;
70
71 let mut model = DefaultModel::default();
72
73 model.load_section(&cfg, "r")?;
74 model.load_section(&cfg, "p")?;
75 model.load_section(&cfg, "e")?;
76 model.load_section(&cfg, "m")?;
77
78 model.load_section(&cfg, "g")?;
79
80 Ok(model)
81 }
82
83 #[allow(clippy::should_implement_trait)]
84 pub async fn from_str(s: &str) -> Result<DefaultModel> {
85 let cfg = Config::from_str(s).await?;
86
87 let mut model = DefaultModel::default();
88
89 model.load_section(&cfg, "r")?;
90 model.load_section(&cfg, "p")?;
91 model.load_section(&cfg, "e")?;
92 model.load_section(&cfg, "m")?;
93
94 model.load_section(&cfg, "g")?;
95
96 Ok(model)
97 }
98
99 fn load_section(&mut self, cfg: &Config, sec: &str) -> Result<()> {
100 let mut i = 1;
101
102 loop {
103 if !self.load_assertion(
104 cfg,
105 sec,
106 &format!("{}{}", sec, self.get_key_suffix(i)),
107 )? {
108 break Ok(());
109 } else {
110 i += 1;
111 }
112 }
113 }
114
115 fn load_assertion(
116 &mut self,
117 cfg: &Config,
118 sec: &str,
119 key: &str,
120 ) -> Result<bool> {
121 let sec_name = match sec {
122 "r" => "request_definition",
123 "p" => "policy_definition",
124 "g" => "role_definition",
125 "e" => "policy_effect",
126 "m" => "matchers",
127 _ => {
128 return Err(ModelError::Other(format!(
129 "Unknown section: `{}`",
130 sec
131 ))
132 .into());
133 }
134 };
135
136 if let Some(val) = cfg.get_str(&format!("{}::{}", sec_name, key)) {
137 Ok(self.add_def(sec, key, val))
138 } else {
139 Ok(false)
140 }
141 }
142
143 fn get_key_suffix(&self, i: u64) -> String {
144 if i == 1 {
145 "".to_owned()
146 } else {
147 i.to_string()
148 }
149 }
150}
151
152impl Model for DefaultModel {
153 fn add_def(&mut self, sec: &str, key: &str, value: &str) -> bool {
154 let mut ast = Assertion {
155 key: key.to_owned(),
156 value: remove_comment(value),
157 ..Default::default()
158 };
159
160 if ast.value.is_empty() {
161 return false;
162 }
163
164 if sec == "r" || sec == "p" {
165 ast.tokens = ast
166 .value
167 .split(',')
168 .map(|x| format!("{}_{}", key, x.trim()))
169 .collect();
170 } else {
171 ast.value = escape_assertion(&ast.value);
172 }
173
174 if let Some(new_model) = self.model.get_mut(sec) {
175 new_model.insert(key.to_owned(), ast);
176 } else {
177 let mut new_ast_map = LinkedHashMap::new();
178 new_ast_map.insert(key.to_owned(), ast);
179 self.model.insert(sec.to_owned(), new_ast_map);
180 }
181
182 true
183 }
184
185 #[inline]
186 fn get_model(&self) -> &HashMap<String, AssertionMap> {
187 &self.model
188 }
189
190 #[inline]
191 fn get_mut_model(&mut self) -> &mut HashMap<String, AssertionMap> {
192 &mut self.model
193 }
194
195 fn build_role_links(
196 &mut self,
197 rm: Arc<RwLock<dyn RoleManager>>,
198 ) -> Result<()> {
199 if let Some(asts) = self.model.get_mut("g") {
200 for ast in asts.values_mut() {
201 ast.build_role_links(Arc::clone(&rm))?;
202 }
203 }
204 Ok(())
205 }
206
207 #[cfg(feature = "incremental")]
208 fn build_incremental_role_links(
209 &mut self,
210 rm: Arc<RwLock<dyn RoleManager>>,
211 d: EventData,
212 ) -> Result<()> {
213 let ast = match d {
214 EventData::AddPolicy(ref sec, ref ptype, _)
215 | EventData::AddPolicies(ref sec, ref ptype, _)
216 | EventData::RemovePolicy(ref sec, ref ptype, _)
217 | EventData::RemovePolicies(ref sec, ref ptype, _)
218 | EventData::RemoveFilteredPolicy(ref sec, ref ptype, _)
219 if sec == "g" =>
220 {
221 self.model
222 .get_mut(sec)
223 .and_then(|ast_map| ast_map.get_mut(ptype))
224 }
225 _ => None,
226 };
227
228 if let Some(ast) = ast {
229 ast.build_incremental_role_links(rm, d)?;
230 }
231
232 Ok(())
233 }
234
235 fn add_policy(
236 &mut self,
237 sec: &str,
238 ptype: &str,
239 rule: Vec<String>,
240 ) -> bool {
241 if let Some(ast_map) = self.model.get_mut(sec) {
242 if let Some(ast) = ast_map.get_mut(ptype) {
243 return ast.policy.insert(rule);
244 }
245 }
246 false
247 }
248
249 fn add_policies(
250 &mut self,
251 sec: &str,
252 ptype: &str,
253 rules: Vec<Vec<String>>,
254 ) -> bool {
255 let mut all_added = true;
256 if let Some(ast_map) = self.model.get_mut(sec) {
257 if let Some(ast) = ast_map.get_mut(ptype) {
258 for rule in &rules {
259 if ast.policy.contains(rule) {
260 all_added = false;
261 return all_added;
262 }
263 }
264 ast.policy.extend(rules);
265 }
266 }
267 all_added
268 }
269
270 fn get_policy(&self, sec: &str, ptype: &str) -> Vec<Vec<String>> {
271 if let Some(t1) = self.model.get(sec) {
272 if let Some(t2) = t1.get(ptype) {
273 return t2.policy.iter().map(|x| x.to_owned()).collect();
274 }
275 }
276 vec![]
277 }
278
279 fn get_filtered_policy(
280 &self,
281 sec: &str,
282 ptype: &str,
283 field_index: usize,
284 field_values: Vec<String>,
285 ) -> Vec<Vec<String>> {
286 let mut res = vec![];
287 if let Some(t1) = self.model.get(sec) {
288 if let Some(t2) = t1.get(ptype) {
289 for rule in t2.policy.iter() {
290 let mut matched = true;
291 for (i, field_value) in field_values.iter().enumerate() {
292 if !field_value.is_empty()
293 && &rule[field_index + i] != field_value
294 {
295 matched = false;
296 break;
297 }
298 }
299 if matched {
300 res.push(rule.iter().map(String::from).collect());
301 }
302 }
303 }
304 }
305 res
306 }
307
308 fn has_policy(&self, sec: &str, ptype: &str, rule: Vec<String>) -> bool {
309 let policy = self.get_policy(sec, ptype);
310 for r in policy {
311 if r == rule {
312 return true;
313 }
314 }
315 false
316 }
317
318 fn get_values_for_field_in_policy(
319 &self,
320 sec: &str,
321 ptype: &str,
322 field_index: usize,
323 ) -> Vec<String> {
324 self.get_policy(sec, ptype)
325 .into_iter()
326 .fold(LinkedHashSet::new(), |mut acc, x| {
327 acc.insert(x[field_index].clone());
328 acc
329 })
330 .into_iter()
331 .collect()
332 }
333
334 fn remove_policy(
335 &mut self,
336 sec: &str,
337 ptype: &str,
338 rule: Vec<String>,
339 ) -> bool {
340 if let Some(ast_map) = self.model.get_mut(sec) {
341 if let Some(ast) = ast_map.get_mut(ptype) {
342 return ast.policy.remove(&rule);
343 }
344 }
345 false
346 }
347
348 fn remove_policies(
349 &mut self,
350 sec: &str,
351 ptype: &str,
352 rules: Vec<Vec<String>>,
353 ) -> bool {
354 let mut all_removed = true;
355 if let Some(ast_map) = self.model.get_mut(sec) {
356 if let Some(ast) = ast_map.get_mut(ptype) {
357 for rule in &rules {
358 if !ast.policy.contains(rule) {
359 all_removed = false;
360 return all_removed;
361 }
362 }
363 for rule in &rules {
364 ast.policy.remove(rule);
365 }
366 }
367 }
368 all_removed
369 }
370
371 fn clear_policy(&mut self) {
372 if let Some(model_p) = self.model.get_mut("p") {
373 for ast in model_p.values_mut() {
374 ast.policy.clear();
375 }
376 }
377
378 if let Some(model_g) = self.model.get_mut("g") {
379 for ast in model_g.values_mut() {
380 ast.policy.clear();
381 }
382 }
383 }
384
385 fn remove_filtered_policy(
386 &mut self,
387 sec: &str,
388 ptype: &str,
389 field_index: usize,
390 field_values: Vec<String>,
391 ) -> (bool, Vec<Vec<String>>) {
392 if field_values.is_empty() {
393 return (false, vec![]);
394 }
395
396 let mut res = false;
397 let mut rules_removed: Vec<Vec<String>> = vec![];
398 if let Some(ast_map) = self.model.get_mut(sec) {
399 if let Some(ast) = ast_map.get_mut(ptype) {
400 for rule in ast.policy.iter() {
401 let mut matched = true;
402 for (i, field_value) in field_values.iter().enumerate() {
403 if !field_value.is_empty()
404 && &rule[field_index + i] != field_value
405 {
406 matched = false;
407 break;
408 }
409 }
410 if matched {
411 res = true;
412 rules_removed.push(rule.clone());
413 }
414 }
415 if res && !rules_removed.is_empty() {
416 for rule in rules_removed.iter() {
417 ast.policy.remove(rule);
418 }
419 }
420 }
421 }
422 (res, rules_removed)
423 }
424
425 fn to_text(&self) -> String {
426 let mut token_patterns = HashMap::new();
427 let p_pattern = regex::Regex::new(r"^p_").unwrap();
428 let r_pattern = regex::Regex::new(r"^r_").unwrap();
429
430 for ptype in ["r", "p"] {
431 if let Some(assertion) = self.model.get(ptype) {
432 for token in &assertion[ptype].tokens {
433 let new_token = p_pattern.replace_all(token, "p.");
434 let new_token = r_pattern.replace_all(&new_token, "r.");
435 token_patterns.insert(token.clone(), new_token.to_string());
436 }
437 }
438 }
439
440 if let Some(assertions) = self.model.get("e") {
441 if let Some(assertion) = assertions.get("e") {
442 if assertion.value.contains("p_eft") {
443 token_patterns
444 .insert("p_eft".to_string(), "p.eft".to_string());
445 }
446 }
447 }
448
449 let mut s = String::new();
450
451 let write_string = |sec: &str, s: &mut String| {
452 if let Some(assertions) = self.model.get(sec) {
453 for (_ptype, assertion) in assertions {
454 let mut value = assertion.value.clone();
455 for (token_pattern, new_token) in &token_patterns {
456 value = value.replace(token_pattern, new_token);
457 }
458 s.push_str(&format!("{} = {}\n", sec, value));
459 }
460 }
461 };
462
463 s.push_str("[request_definition]\n");
464 write_string("r", &mut s);
465 s.push_str("[policy_definition]\n");
466 write_string("p", &mut s);
467
468 if self.model.contains_key("g") {
469 s.push_str("[role_definition]\n");
470 if let Some(assertions) = self.model.get("g") {
471 for (ptype, assertion) in assertions {
472 s.push_str(&format!("{} = {}\n", ptype, assertion.value));
473 }
474 }
475 }
476
477 s.push_str("[policy_effect]\n");
478 write_string("e", &mut s);
479 s.push_str("[matchers]\n");
480 write_string("m", &mut s);
481
482 s
483 }
484
485 fn as_any(&self) -> &dyn std::any::Any {
486 self
487 }
488
489 fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
490 self
491 }
492}
493
494#[cfg(test)]
495mod tests {
496 use crate::prelude::*;
497
498 #[cfg(not(target_arch = "wasm32"))]
499 #[cfg_attr(
500 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
501 async_std::test
502 )]
503 #[cfg_attr(
504 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
505 tokio::test
506 )]
507 async fn test_basic_model() {
508 let m = DefaultModel::from_file("examples/basic_model.conf")
509 .await
510 .unwrap();
511
512 let adapter = FileAdapter::new("examples/basic_policy.csv");
513 let e = Enforcer::new(m, adapter).await.unwrap();
514
515 assert!(e.enforce(("alice", "data1", "read")).unwrap());
516 assert!(!e.enforce(("alice", "data1", "write")).unwrap());
517 assert!(!e.enforce(("alice", "data2", "read")).unwrap());
518 assert!(!e.enforce(("alice", "data2", "write")).unwrap());
519 assert!(!e.enforce(("bob", "data1", "read")).unwrap());
520 assert!(!e.enforce(("bob", "data1", "write")).unwrap());
521 assert!(!e.enforce(("bob", "data2", "read")).unwrap());
522 assert!(e.enforce(("bob", "data2", "write")).unwrap());
523 }
524
525 #[cfg(not(target_arch = "wasm32"))]
526 #[cfg_attr(
527 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
528 async_std::test
529 )]
530 #[cfg_attr(
531 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
532 tokio::test
533 )]
534 async fn test_basic_model_no_policy() {
535 let m = DefaultModel::from_file("examples/basic_model.conf")
536 .await
537 .unwrap();
538
539 let adapter = MemoryAdapter::default();
540 let e = Enforcer::new(m, adapter).await.unwrap();
541
542 assert!(!e.enforce(("alice", "data1", "read")).unwrap());
543 assert!(!e.enforce(("alice", "data1", "write")).unwrap());
544 assert!(!e.enforce(("alice", "data2", "read")).unwrap());
545 assert!(!e.enforce(("alice", "data2", "write")).unwrap());
546 assert!(!e.enforce(("bob", "data1", "read")).unwrap());
547 assert!(!e.enforce(("bob", "data1", "write")).unwrap());
548 assert!(!e.enforce(("bob", "data2", "read")).unwrap());
549 assert!(!e.enforce(("bob", "data2", "write")).unwrap());
550 }
551
552 #[cfg(not(target_arch = "wasm32"))]
553 #[cfg_attr(
554 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
555 async_std::test
556 )]
557 #[cfg_attr(
558 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
559 tokio::test
560 )]
561 async fn test_basic_model_with_root() {
562 let m = DefaultModel::from_file("examples/basic_with_root_model.conf")
563 .await
564 .unwrap();
565
566 let adapter = FileAdapter::new("examples/basic_policy.csv");
567 let e = Enforcer::new(m, adapter).await.unwrap();
568
569 assert!(e.enforce(("alice", "data1", "read")).unwrap());
570 assert!(e.enforce(("bob", "data2", "write")).unwrap());
571 assert!(e.enforce(("root", "data1", "read")).unwrap());
572 assert!(e.enforce(("root", "data1", "write")).unwrap());
573 assert!(e.enforce(("root", "data2", "read")).unwrap());
574 assert!(e.enforce(("root", "data2", "write")).unwrap());
575 assert!(!e.enforce(("alice", "data1", "write")).unwrap());
576 assert!(!e.enforce(("alice", "data2", "read")).unwrap());
577 assert!(!e.enforce(("alice", "data2", "write")).unwrap());
578 assert!(!e.enforce(("bob", "data1", "read")).unwrap());
579 assert!(!e.enforce(("bob", "data1", "write")).unwrap());
580 assert!(!e.enforce(("bob", "data2", "read")).unwrap());
581 }
582
583 #[cfg(not(target_arch = "wasm32"))]
584 #[cfg_attr(
585 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
586 async_std::test
587 )]
588 #[cfg_attr(
589 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
590 tokio::test
591 )]
592 async fn test_basic_model_with_root_no_policy() {
593 let m = DefaultModel::from_file("examples/basic_with_root_model.conf")
594 .await
595 .unwrap();
596
597 let adapter = MemoryAdapter::default();
598 let e = Enforcer::new(m, adapter).await.unwrap();
599
600 assert!(!e.enforce(("alice", "data1", "read")).unwrap());
601 assert!(!e.enforce(("bob", "data2", "write")).unwrap());
602 assert!(e.enforce(("root", "data1", "read")).unwrap());
603 assert!(e.enforce(("root", "data1", "write")).unwrap());
604 assert!(e.enforce(("root", "data2", "read")).unwrap());
605 assert!(e.enforce(("root", "data2", "write")).unwrap());
606 assert!(!e.enforce(("alice", "data1", "write")).unwrap());
607 assert!(!e.enforce(("alice", "data2", "read")).unwrap());
608 assert!(!e.enforce(("alice", "data2", "write")).unwrap());
609 assert!(!e.enforce(("bob", "data1", "read")).unwrap());
610 assert!(!e.enforce(("bob", "data1", "write")).unwrap());
611 assert!(!e.enforce(("bob", "data2", "read")).unwrap());
612 }
613
614 #[cfg(not(target_arch = "wasm32"))]
615 #[cfg_attr(
616 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
617 async_std::test
618 )]
619 #[cfg_attr(
620 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
621 tokio::test
622 )]
623 async fn test_basic_model_without_users() {
624 let m =
625 DefaultModel::from_file("examples/basic_without_users_model.conf")
626 .await
627 .unwrap();
628
629 let adapter =
630 FileAdapter::new("examples/basic_without_users_policy.csv");
631 let e = Enforcer::new(m, adapter).await.unwrap();
632
633 assert!(e.enforce(("data1", "read")).unwrap());
634 assert!(!e.enforce(("data1", "write")).unwrap());
635 assert!(!e.enforce(("data2", "read")).unwrap());
636 assert!(e.enforce(("data2", "write")).unwrap());
637 }
638
639 #[cfg(not(target_arch = "wasm32"))]
640 #[cfg_attr(
641 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
642 async_std::test
643 )]
644 #[cfg_attr(
645 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
646 tokio::test
647 )]
648 async fn test_basic_model_without_resources() {
649 let m = DefaultModel::from_file(
650 "examples/basic_without_resources_model.conf",
651 )
652 .await
653 .unwrap();
654
655 let adapter =
656 FileAdapter::new("examples/basic_without_resources_policy.csv");
657 let e = Enforcer::new(m, adapter).await.unwrap();
658
659 assert!(e.enforce(("alice", "read")).unwrap());
660 assert!(e.enforce(("bob", "write")).unwrap());
661 assert!(!e.enforce(("alice", "write")).unwrap());
662 assert!(!e.enforce(("bob", "read")).unwrap());
663 }
664
665 #[cfg(not(target_arch = "wasm32"))]
666 #[cfg_attr(
667 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
668 async_std::test
669 )]
670 #[cfg_attr(
671 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
672 tokio::test
673 )]
674 async fn test_rbac_model() {
675 let m = DefaultModel::from_file("examples/rbac_model.conf")
676 .await
677 .unwrap();
678
679 let adapter = FileAdapter::new("examples/rbac_policy.csv");
680 let e = Enforcer::new(m, adapter).await.unwrap();
681
682 assert_eq!(true, e.enforce(("alice", "data1", "read")).unwrap());
683 assert_eq!(false, e.enforce(("alice", "data1", "write")).unwrap());
684 assert_eq!(true, e.enforce(("alice", "data2", "read")).unwrap());
685 assert_eq!(true, e.enforce(("alice", "data2", "write")).unwrap());
686 assert_eq!(false, e.enforce(("bob", "data1", "read")).unwrap());
687 assert_eq!(false, e.enforce(("bob", "data1", "write")).unwrap());
688 assert_eq!(false, e.enforce(("bob", "data2", "read")).unwrap());
689 assert_eq!(true, e.enforce(("bob", "data2", "write")).unwrap());
690 }
691
692 #[cfg(not(target_arch = "wasm32"))]
693 #[cfg_attr(
694 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
695 async_std::test
696 )]
697 #[cfg_attr(
698 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
699 tokio::test
700 )]
701 async fn test_rbac_model_with_resource_roles() {
702 let m = DefaultModel::from_file(
703 "examples/rbac_with_resource_roles_model.conf",
704 )
705 .await
706 .unwrap();
707
708 let adapter =
709 FileAdapter::new("examples/rbac_with_resource_roles_policy.csv");
710 let e = Enforcer::new(m, adapter).await.unwrap();
711
712 assert_eq!(true, e.enforce(("alice", "data1", "read")).unwrap());
713 assert_eq!(true, e.enforce(("alice", "data1", "write")).unwrap());
714 assert_eq!(false, e.enforce(("alice", "data2", "read")).unwrap());
715 assert_eq!(true, e.enforce(("alice", "data2", "write")).unwrap());
716 assert_eq!(false, e.enforce(("bob", "data1", "read")).unwrap());
717 assert_eq!(false, e.enforce(("bob", "data1", "write")).unwrap());
718 assert_eq!(false, e.enforce(("bob", "data2", "read")).unwrap());
719 assert_eq!(true, e.enforce(("bob", "data2", "write")).unwrap());
720 }
721
722 #[cfg(not(target_arch = "wasm32"))]
723 #[cfg_attr(
724 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
725 async_std::test
726 )]
727 #[cfg_attr(
728 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
729 tokio::test
730 )]
731 async fn test_rbac_model_with_domains() {
732 let m =
733 DefaultModel::from_file("examples/rbac_with_domains_model.conf")
734 .await
735 .unwrap();
736
737 let adapter = FileAdapter::new("examples/rbac_with_domains_policy.csv");
738 let e = Enforcer::new(m, adapter).await.unwrap();
739
740 assert_eq!(
741 true,
742 e.enforce(("alice", "domain1", "data1", "read")).unwrap()
743 );
744 assert_eq!(
745 true,
746 e.enforce(("alice", "domain1", "data1", "write")).unwrap()
747 );
748 assert_eq!(
749 false,
750 e.enforce(("alice", "domain1", "data2", "read")).unwrap()
751 );
752 assert_eq!(
753 false,
754 e.enforce(("alice", "domain1", "data2", "write")).unwrap()
755 );
756 assert_eq!(
757 false,
758 e.enforce(("bob", "domain2", "data1", "read")).unwrap()
759 );
760 assert_eq!(
761 false,
762 e.enforce(("bob", "domain2", "data1", "write")).unwrap()
763 );
764 assert_eq!(
765 true,
766 e.enforce(("bob", "domain2", "data2", "read")).unwrap()
767 );
768 assert_eq!(
769 true,
770 e.enforce(("bob", "domain2", "data2", "write")).unwrap()
771 );
772 }
773
774 #[cfg(not(target_arch = "wasm32"))]
775 #[cfg_attr(
776 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
777 async_std::test
778 )]
779 #[cfg_attr(
780 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
781 tokio::test
782 )]
783 async fn test_rbac_model_with_domains_runtime() {
784 let m =
785 DefaultModel::from_file("examples/rbac_with_domains_model.conf")
786 .await
787 .unwrap();
788
789 let adapter = MemoryAdapter::default();
790 let mut e = Enforcer::new(m, adapter).await.unwrap();
791 e.add_policy(
792 vec!["admin", "domain1", "data1", "read"]
793 .iter()
794 .map(|s| s.to_string())
795 .collect(),
796 )
797 .await
798 .unwrap();
799 e.add_policy(
800 vec!["admin", "domain1", "data1", "write"]
801 .iter()
802 .map(|s| s.to_string())
803 .collect(),
804 )
805 .await
806 .unwrap();
807 e.add_policy(
808 vec!["admin", "domain2", "data2", "read"]
809 .iter()
810 .map(|s| s.to_string())
811 .collect(),
812 )
813 .await
814 .unwrap();
815 e.add_policy(
816 vec!["admin", "domain2", "data2", "write"]
817 .iter()
818 .map(|s| s.to_string())
819 .collect(),
820 )
821 .await
822 .unwrap();
823
824 e.add_grouping_policy(
825 vec!["alice", "admin", "domain1"]
826 .iter()
827 .map(|s| s.to_string())
828 .collect(),
829 )
830 .await
831 .unwrap();
832 e.add_grouping_policy(
833 vec!["bob", "admin", "domain2"]
834 .iter()
835 .map(|s| s.to_string())
836 .collect(),
837 )
838 .await
839 .unwrap();
840
841 assert_eq!(
842 true,
843 e.enforce(("alice", "domain1", "data1", "read")).unwrap()
844 );
845 assert_eq!(
846 true,
847 e.enforce(("alice", "domain1", "data1", "write")).unwrap()
848 );
849 assert_eq!(
850 false,
851 e.enforce(("alice", "domain1", "data2", "read")).unwrap()
852 );
853 assert_eq!(
854 false,
855 e.enforce(("alice", "domain1", "data2", "write")).unwrap()
856 );
857 assert_eq!(
858 false,
859 e.enforce(("bob", "domain2", "data1", "read")).unwrap()
860 );
861 assert_eq!(
862 false,
863 e.enforce(("bob", "domain2", "data1", "write")).unwrap()
864 );
865 assert_eq!(
866 true,
867 e.enforce(("bob", "domain2", "data2", "read")).unwrap()
868 );
869 assert_eq!(
870 true,
871 e.enforce(("bob", "domain2", "data2", "write")).unwrap()
872 );
873
874 assert_eq!(
875 true,
876 e.remove_filtered_policy(
877 1,
878 vec!["domain1", "data1"]
879 .iter()
880 .map(|s| s.to_string())
881 .collect(),
882 )
883 .await
884 .unwrap()
885 );
886
887 assert_eq!(
888 false,
889 e.enforce(("alice", "domain1", "data1", "read")).unwrap()
890 );
891 assert_eq!(
892 false,
893 e.enforce(("alice", "domain1", "data1", "write")).unwrap()
894 );
895 assert_eq!(
896 false,
897 e.enforce(("alice", "domain1", "data2", "read")).unwrap()
898 );
899 assert_eq!(
900 false,
901 e.enforce(("alice", "domain1", "data2", "write")).unwrap()
902 );
903 assert_eq!(
904 false,
905 e.enforce(("bob", "domain2", "data1", "read")).unwrap()
906 );
907 assert_eq!(
908 false,
909 e.enforce(("bob", "domain2", "data1", "write")).unwrap()
910 );
911 assert_eq!(
912 true,
913 e.enforce(("bob", "domain2", "data2", "read")).unwrap()
914 );
915 assert_eq!(
916 true,
917 e.enforce(("bob", "domain2", "data2", "write")).unwrap()
918 );
919
920 assert_eq!(
921 true,
922 e.remove_policy(
923 vec!["admin", "domain2", "data2", "read"]
924 .iter()
925 .map(|s| s.to_string())
926 .collect(),
927 )
928 .await
929 .unwrap()
930 );
931
932 assert_eq!(
933 false,
934 e.enforce(("alice", "domain1", "data1", "read")).unwrap()
935 );
936 assert_eq!(
937 false,
938 e.enforce(("alice", "domain1", "data1", "write")).unwrap()
939 );
940 assert_eq!(
941 false,
942 e.enforce(("alice", "domain1", "data2", "read")).unwrap()
943 );
944 assert_eq!(
945 false,
946 e.enforce(("alice", "domain1", "data2", "write")).unwrap()
947 );
948 assert_eq!(
949 false,
950 e.enforce(("bob", "domain2", "data1", "read")).unwrap()
951 );
952 assert_eq!(
953 false,
954 e.enforce(("bob", "domain2", "data1", "write")).unwrap()
955 );
956 assert_eq!(
957 false,
958 e.enforce(("bob", "domain2", "data2", "read")).unwrap()
959 );
960 assert_eq!(
961 true,
962 e.enforce(("bob", "domain2", "data2", "write")).unwrap()
963 );
964 }
965
966 #[cfg(not(target_arch = "wasm32"))]
967 #[cfg_attr(
968 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
969 async_std::test
970 )]
971 #[cfg_attr(
972 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
973 tokio::test
974 )]
975 async fn test_rbac_model_with_domains_at_runtime_mock_adapter() {
976 let m =
977 DefaultModel::from_file("examples/rbac_with_domains_model.conf")
978 .await
979 .unwrap();
980
981 let adapter = FileAdapter::new("examples/rbac_with_domains_policy.csv");
982 let mut e = Enforcer::new(m, adapter).await.unwrap();
983
984 e.add_policy(
985 vec!["admin", "domain3", "data1", "read"]
986 .iter()
987 .map(|s| s.to_string())
988 .collect(),
989 )
990 .await
991 .unwrap();
992 e.add_grouping_policy(
993 vec!["alice", "admin", "domain3"]
994 .iter()
995 .map(|s| s.to_string())
996 .collect(),
997 )
998 .await
999 .unwrap();
1000
1001 assert_eq!(
1002 true,
1003 e.enforce(("alice", "domain3", "data1", "read")).unwrap()
1004 );
1005 assert_eq!(
1006 true,
1007 e.enforce(("alice", "domain1", "data1", "read")).unwrap()
1008 );
1009
1010 e.remove_filtered_policy(
1011 1,
1012 vec!["domain1", "data1"]
1013 .iter()
1014 .map(|s| s.to_string())
1015 .collect(),
1016 )
1017 .await
1018 .unwrap();
1019 assert_eq!(
1020 false,
1021 e.enforce(("alice", "domain1", "data1", "read")).unwrap()
1022 );
1023 assert_eq!(
1024 true,
1025 e.enforce(("bob", "domain2", "data2", "read")).unwrap()
1026 );
1027
1028 e.remove_policy(
1029 vec!["admin", "domain2", "data2", "read"]
1030 .iter()
1031 .map(|s| s.to_string())
1032 .collect(),
1033 )
1034 .await
1035 .unwrap();
1036 assert_eq!(
1037 false,
1038 e.enforce(("bob", "domain2", "data2", "read")).unwrap()
1039 );
1040 }
1041
1042 #[cfg(not(target_arch = "wasm32"))]
1043 #[cfg_attr(
1044 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
1045 async_std::test
1046 )]
1047 #[cfg_attr(
1048 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
1049 tokio::test
1050 )]
1051 async fn test_rbac_model_with_deny() {
1052 let m = DefaultModel::from_file("examples/rbac_with_deny_model.conf")
1053 .await
1054 .unwrap();
1055
1056 let adapter = FileAdapter::new("examples/rbac_with_deny_policy.csv");
1057 let e = Enforcer::new(m, adapter).await.unwrap();
1058
1059 assert_eq!(true, e.enforce(("alice", "data1", "read")).unwrap());
1060 assert_eq!(false, e.enforce(("alice", "data1", "write")).unwrap());
1061 assert_eq!(true, e.enforce(("alice", "data2", "read")).unwrap());
1062 assert_eq!(false, e.enforce(("alice", "data2", "write")).unwrap());
1063 assert_eq!(false, e.enforce(("bob", "data1", "read")).unwrap());
1064 assert_eq!(false, e.enforce(("bob", "data1", "write")).unwrap());
1065 assert_eq!(false, e.enforce(("bob", "data2", "read")).unwrap());
1066 assert_eq!(true, e.enforce(("bob", "data2", "write")).unwrap());
1067 }
1068
1069 #[cfg(not(target_arch = "wasm32"))]
1070 #[cfg_attr(
1071 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
1072 async_std::test
1073 )]
1074 #[cfg_attr(
1075 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
1076 tokio::test
1077 )]
1078 async fn test_rbac_model_with_not_deny() {
1079 let m =
1080 DefaultModel::from_file("examples/rbac_with_not_deny_model.conf")
1081 .await
1082 .unwrap();
1083
1084 let adapter = FileAdapter::new("examples/rbac_with_deny_policy.csv");
1085 let e = Enforcer::new(m, adapter).await.unwrap();
1086
1087 assert_eq!(false, e.enforce(("alice", "data2", "write")).unwrap());
1088 }
1089
1090 #[cfg(not(target_arch = "wasm32"))]
1091 #[cfg_attr(
1092 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
1093 async_std::test
1094 )]
1095 #[cfg_attr(
1096 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
1097 tokio::test
1098 )]
1099 async fn test_rbac_model_with_custom_data() {
1100 let m = DefaultModel::from_file("examples/rbac_model.conf")
1101 .await
1102 .unwrap();
1103
1104 let adapter = FileAdapter::new("examples/rbac_policy.csv");
1105 let mut e = Enforcer::new(m, adapter).await.unwrap();
1106
1107 e.add_grouping_policy(
1108 vec!["bob", "data2_admin", "custom_data"]
1109 .iter()
1110 .map(|s| s.to_string())
1111 .collect(),
1112 )
1113 .await
1114 .unwrap();
1115
1116 assert_eq!(true, e.enforce(("alice", "data1", "read")).unwrap());
1117 assert_eq!(false, e.enforce(("alice", "data1", "write")).unwrap());
1118 assert_eq!(true, e.enforce(("alice", "data2", "read")).unwrap());
1119 assert_eq!(true, e.enforce(("alice", "data2", "write")).unwrap());
1120 assert_eq!(false, e.enforce(("bob", "data1", "read")).unwrap());
1121 assert_eq!(false, e.enforce(("bob", "data1", "write")).unwrap());
1122 assert_eq!(true, e.enforce(("bob", "data2", "read")).unwrap());
1123 assert_eq!(true, e.enforce(("bob", "data2", "write")).unwrap());
1124
1125 e.remove_grouping_policy(
1126 vec!["bob", "data2_admin", "custom_data"]
1127 .iter()
1128 .map(|s| s.to_string())
1129 .collect(),
1130 )
1131 .await
1132 .unwrap();
1133
1134 assert_eq!(true, e.enforce(("alice", "data1", "read")).unwrap());
1135 assert_eq!(false, e.enforce(("alice", "data1", "write")).unwrap());
1136 assert_eq!(true, e.enforce(("alice", "data2", "read")).unwrap());
1137 assert_eq!(true, e.enforce(("alice", "data2", "write")).unwrap());
1138 assert_eq!(false, e.enforce(("bob", "data1", "read")).unwrap());
1139 assert_eq!(false, e.enforce(("bob", "data1", "write")).unwrap());
1140 assert_eq!(false, e.enforce(("bob", "data2", "read")).unwrap());
1141 assert_eq!(true, e.enforce(("bob", "data2", "write")).unwrap());
1142 }
1143
1144 #[cfg(not(target_arch = "wasm32"))]
1145 #[cfg_attr(
1146 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
1147 async_std::test
1148 )]
1149 #[cfg_attr(
1150 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
1151 tokio::test
1152 )]
1153 async fn test_rbac_model_using_in_op() {
1154 let m = DefaultModel::from_file(
1155 "examples/rbac_model_matcher_using_in_op.conf",
1156 )
1157 .await
1158 .unwrap();
1159
1160 let adapter = FileAdapter::new("examples/rbac_policy.csv");
1161 let e = Enforcer::new(m, adapter).await.unwrap();
1162
1163 assert_eq!(true, e.enforce(("alice", "data1", "read")).unwrap());
1164 assert_eq!(false, e.enforce(("alice", "data1", "write")).unwrap());
1165 assert_eq!(true, e.enforce(("bob", "data2", "write")).unwrap());
1166 assert_eq!(true, e.enforce(("alice", "data2", "write")).unwrap());
1167 assert_eq!(true, e.enforce(("alice", "data2", "read")).unwrap());
1168 assert_eq!(true, e.enforce(("guest", "data2", "read")).unwrap());
1169 assert_eq!(true, e.enforce(("alice", "data3", "read")).unwrap());
1170 assert_eq!(true, e.enforce(("bob", "data3", "read")).unwrap());
1171 }
1172
1173 #[cfg(not(target_arch = "wasm32"))]
1174 #[cfg_attr(
1175 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
1176 async_std::test
1177 )]
1178 #[cfg_attr(
1179 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
1180 tokio::test
1181 )]
1182 async fn test_abac() {
1183 use serde::Serialize;
1184
1185 let m = DefaultModel::from_file("examples/abac_model.conf")
1186 .await
1187 .unwrap();
1188
1189 let adapter = MemoryAdapter::default();
1190 let e = Enforcer::new(m, adapter).await.unwrap();
1191
1192 #[derive(Serialize, Hash)]
1193 pub struct Book<'a> {
1194 owner: &'a str,
1195 }
1196
1197 assert_eq!(
1198 false,
1199 e.enforce(("alice", Book { owner: "bob" }, "read")).unwrap()
1200 );
1201 assert_eq!(
1202 true,
1203 e.enforce(("alice", Book { owner: "alice" }, "read"))
1204 .unwrap()
1205 );
1206 }
1207}