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 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    // Precompiled matcher expressions - compiled during Model initialization
29    // Keys are full matcher names (e.g., "m", "m2", "m3")
30    compiled_matchers: HashMap<String, AST>,
31}
32
33impl DefaultModel {
34    // Compiles all matcher expressions after Model loading is complete
35    // Should be called before Enforcer is used
36    pub fn compile_matchers(&mut self, engine: &Engine) -> Result<()> {
37        self.compiled_matchers.clear();
38
39        // Only compile matchers from the 'm' section
40        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                // Directly use the complete matcher key as HashMap key
56                self.compiled_matchers.insert(key.clone(), compiled);
57            }
58        }
59        Ok(())
60    }
61
62    // Gets the precompiled matcher - O(1) lookup, simple and direct
63    #[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}