casbin/model/
assertion.rs

1use crate::{
2    error::{ModelError, PolicyError},
3    rbac::{DefaultRoleManager, RoleManager},
4    Result,
5};
6
7#[cfg(feature = "incremental")]
8use crate::emitter::EventData;
9
10use hashlink::{LinkedHashMap, LinkedHashSet};
11use parking_lot::RwLock;
12
13use std::sync::Arc;
14
15pub type AssertionMap = LinkedHashMap<String, Assertion>;
16
17#[derive(Clone)]
18pub struct Assertion {
19    pub key: String,
20    pub value: String,
21    pub tokens: Vec<String>,
22    pub policy: LinkedHashSet<Vec<String>>,
23    pub rm: Arc<RwLock<dyn RoleManager>>,
24}
25
26impl Default for Assertion {
27    fn default() -> Self {
28        Assertion {
29            key: String::new(),
30            value: String::new(),
31            tokens: vec![],
32            policy: LinkedHashSet::new(),
33            rm: Arc::new(RwLock::new(DefaultRoleManager::new(0))),
34        }
35    }
36}
37
38impl Assertion {
39    #[inline]
40    pub fn get_policy(&self) -> &LinkedHashSet<Vec<String>> {
41        &self.policy
42    }
43
44    #[inline]
45    pub fn get_mut_policy(&mut self) -> &mut LinkedHashSet<Vec<String>> {
46        &mut self.policy
47    }
48
49    pub fn build_role_links(
50        &mut self,
51        rm: Arc<RwLock<dyn RoleManager>>,
52    ) -> Result<()> {
53        let count = self.value.matches('_').count();
54        if count < 2 {
55            return Err(ModelError::P(
56                r#"the number of "_" in role definition should be at least 2"#
57                    .to_owned(),
58            )
59            .into());
60        }
61        for rule in &self.policy {
62            if rule.len() < count {
63                return Err(PolicyError::UnmatchPolicyDefinition(
64                    count,
65                    rule.len(),
66                )
67                .into());
68            }
69            if count == 2 {
70                rm.write().add_link(&rule[0], &rule[1], None);
71            } else if count == 3 {
72                rm.write().add_link(&rule[0], &rule[1], Some(&rule[2]));
73            } else if count >= 4 {
74                return Err(ModelError::P(
75                    "Multiple domains are not supported".to_owned(),
76                )
77                .into());
78            }
79        }
80        self.rm = Arc::clone(&rm);
81        Ok(())
82    }
83
84    #[cfg(feature = "incremental")]
85    pub fn build_incremental_role_links(
86        &mut self,
87        rm: Arc<RwLock<dyn RoleManager>>,
88        d: EventData,
89    ) -> Result<()> {
90        let count = self.value.matches('_').count();
91        if count < 2 {
92            return Err(ModelError::P(
93                r#"the number of "_" in role definition should be at least 2"#
94                    .to_owned(),
95            )
96            .into());
97        }
98
99        if let Some((insert, rules)) = match d {
100            EventData::AddPolicy(_, _, rule) => Some((true, vec![rule])),
101            EventData::AddPolicies(_, _, rules) => Some((true, rules)),
102            EventData::RemovePolicy(_, _, rule) => Some((false, vec![rule])),
103            EventData::RemovePolicies(_, _, rules) => Some((false, rules)),
104            EventData::RemoveFilteredPolicy(_, _, rules) => {
105                Some((false, rules))
106            }
107            _ => None,
108        } {
109            for rule in rules {
110                if rule.len() < count {
111                    return Err(PolicyError::UnmatchPolicyDefinition(
112                        count,
113                        rule.len(),
114                    )
115                    .into());
116                }
117                if count == 2 {
118                    if insert {
119                        rm.write().add_link(&rule[0], &rule[1], None);
120                    } else {
121                        rm.write().delete_link(&rule[0], &rule[1], None)?;
122                    }
123                } else if count == 3 {
124                    if insert {
125                        rm.write().add_link(&rule[0], &rule[1], Some(&rule[2]));
126                    } else {
127                        rm.write().delete_link(
128                            &rule[0],
129                            &rule[1],
130                            Some(&rule[2]),
131                        )?;
132                    }
133                } else if count >= 4 {
134                    return Err(ModelError::P(
135                        "Multiple domains are not supported".to_owned(),
136                    )
137                    .into());
138                }
139            }
140
141            self.rm = Arc::clone(&rm);
142        }
143
144        Ok(())
145    }
146}