casbin/model/
default_model.rs

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}