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