1mod utils;
16use async_trait::async_trait;
17use casbin::{
18 error::{AdapterError, ModelError},
19 Adapter, Filter, Model, Result,
20};
21use std::fmt::Write;
22use utils::*;
23
24#[derive(Default)]
25pub struct StringAdapter {
26 policy: String,
27 is_filtered: bool,
28}
29
30impl StringAdapter {
31 pub fn new(s: impl ToString) -> Self {
32 Self {
33 policy: s.to_string(),
34 is_filtered: false,
35 }
36 }
37}
38
39#[async_trait]
40impl Adapter for StringAdapter {
41 async fn load_policy(&mut self, m: &mut dyn Model) -> Result<()> {
42 let policies = self.policy.split("\n");
43 for line in policies {
44 load_policy_line(line, m);
45 }
46 Ok(())
47 }
48
49 async fn load_filtered_policy<'a>(&mut self, m: &mut dyn Model, f: Filter<'a>) -> Result<()> {
50 let policies = self.policy.split("\n");
51 for line in policies {
52 if let Some(tokens) = parse_csv_line(line) {
53 let sec = &tokens[0];
54 let ptype = &tokens[1];
55 let rule = tokens[1..].to_vec().clone();
56 let mut is_filtered = false;
57
58 if sec == "p" {
59 for (i, r) in f.p.iter().enumerate() {
60 if !r.is_empty() && r != &rule[i + 1] {
61 is_filtered = true;
62 }
63 }
64 }
65 if sec == "g" {
66 for (i, r) in f.g.iter().enumerate() {
67 if !r.is_empty() && r != &rule[i + 1] {
68 is_filtered = true;
69 }
70 }
71 }
72 if !is_filtered {
73 if let Some(ast_map) = m.get_mut_model().get_mut(sec) {
74 if let Some(ast) = ast_map.get_mut(ptype) {
75 ast.get_mut_policy().insert(rule);
76 }
77 }
78 } else {
79 self.is_filtered = true;
80 }
81 }
82 }
83 Ok(())
84 }
85
86 async fn save_policy(&mut self, m: &mut dyn Model) -> Result<()> {
87 let mut policies = String::new();
88 let ast_map = m
89 .get_model()
90 .get("p")
91 .ok_or_else(|| ModelError::P("Missing policy definition in conf file".to_owned()))?;
92
93 for (ptype, ast) in ast_map {
94 for rule in ast.get_policy() {
95 writeln!(policies, "{}, {}", ptype, rule.join(", "))
96 .map_err(|e| AdapterError(e.into()))?;
97 }
98 }
99
100 if let Some(ast_map) = m.get_model().get("g") {
101 for (ptype, ast) in ast_map {
102 for rule in ast.get_policy() {
103 writeln!(policies, "{}, {}", ptype, rule.join(", "))
104 .map_err(|e| AdapterError(e.into()))?;
105 }
106 }
107 }
108
109 self.policy = policies;
110 Ok(())
111 }
112
113 async fn clear_policy(&mut self) -> Result<()> {
114 self.policy.clear();
115 self.is_filtered = false;
116 Ok(())
117 }
118
119 async fn add_policy(&mut self, _sec: &str, _ptype: &str, _rule: Vec<String>) -> Result<bool> {
120 Err(casbin::Error::AdapterError(AdapterError(
122 "not implemented".to_string().into(),
123 )))
124 }
125
126 async fn add_policies(
127 &mut self,
128 _sec: &str,
129 _ptype: &str,
130 _rules: Vec<Vec<String>>,
131 ) -> Result<bool> {
132 Err(casbin::Error::AdapterError(AdapterError(
134 "not implemented".to_string().into(),
135 )))
136 }
137
138 async fn remove_policy(
139 &mut self,
140 _sec: &str,
141 _ptype: &str,
142 _rule: Vec<String>,
143 ) -> Result<bool> {
144 Err(casbin::Error::AdapterError(AdapterError(
146 "not implemented".to_string().into(),
147 )))
148 }
149
150 async fn remove_policies(
151 &mut self,
152 _sec: &str,
153 _ptype: &str,
154 _rule: Vec<Vec<String>>,
155 ) -> Result<bool> {
156 Err(casbin::Error::AdapterError(AdapterError(
158 "not implemented".to_string().into(),
159 )))
160 }
161
162 async fn remove_filtered_policy(
163 &mut self,
164 _sec: &str,
165 _ptype: &str,
166 _field_index: usize,
167 _field_values: Vec<String>,
168 ) -> Result<bool> {
169 Err(casbin::Error::AdapterError(AdapterError(
171 "not implemented".to_string().into(),
172 )))
173 }
174
175 fn is_filtered(&self) -> bool {
176 self.is_filtered
177 }
178}
179
180#[cfg(test)]
181mod tests {
182 use crate::StringAdapter;
183 use casbin::{Adapter, CoreApi, Filter};
184 use casbin::{DefaultModel, Enforcer};
185
186 #[cfg_attr(feature = "runtime-async-std", async_std::test)]
187 #[cfg_attr(feature = "runtime-tokio", tokio::test)]
188 async fn test_load_policy() {
189 let policy = "p, alice, data1, read\np, bob, data2, write";
190 let mut adapter = StringAdapter::new(policy);
191 let mut model = DefaultModel::from_file("tests/rbac_model.conf")
192 .await
193 .unwrap();
194
195 adapter.load_policy(&mut model).await.unwrap();
196 let enforcer = Enforcer::new(model, adapter).await.unwrap();
197
198 assert!(enforcer.enforce(("alice", "data1", "read")).unwrap());
199 assert!(enforcer.enforce(("bob", "data2", "write")).unwrap());
200 assert!(!enforcer.enforce(("alice", "data2", "read")).unwrap());
201 }
202
203 #[cfg_attr(feature = "runtime-async-std", async_std::test)]
204 #[cfg_attr(feature = "runtime-tokio", tokio::test)]
205 async fn test_save_policy() {
206 let policy = "p, alice, data1, read\np, bob, data2, write";
207 let mut adapter = StringAdapter::new(policy);
208 let mut model = DefaultModel::from_file("tests/rbac_model.conf")
209 .await
210 .unwrap();
211
212 adapter.load_policy(&mut model).await.unwrap();
213 adapter.save_policy(&mut model).await.unwrap();
214
215 assert_eq!(
216 adapter.policy,
217 "p, alice, data1, read\np, bob, data2, write\n"
218 );
219 }
220
221 #[cfg_attr(feature = "runtime-async-std", async_std::test)]
222 #[cfg_attr(feature = "runtime-tokio", tokio::test)]
223 async fn test_clear_policy() {
224 let policy = "p, alice, data1, read\np, bob, data2, write";
225 let mut adapter = StringAdapter::new(policy);
226 let mut model = DefaultModel::from_file("tests/rbac_model.conf")
227 .await
228 .unwrap();
229
230 adapter.load_policy(&mut model).await.unwrap();
231 adapter.clear_policy().await.unwrap();
232
233 assert_eq!(adapter.policy, "");
234 assert!(!adapter.is_filtered);
235 }
236
237 #[cfg_attr(feature = "runtime-async-std", async_std::test)]
238 #[cfg_attr(feature = "runtime-tokio", tokio::test)]
239 async fn test_is_filtered() {
240 let policy = "p, alice, data1, read\np, bob, data2, write";
241 let mut adapter = StringAdapter::new(policy);
242 let mut model = DefaultModel::from_file("tests/rbac_model.conf")
243 .await
244 .unwrap();
245
246 let filter = Filter {
247 p: vec!["alice"],
248 g: vec![],
249 };
250
251 adapter
252 .load_filtered_policy(&mut model, filter)
253 .await
254 .unwrap();
255
256 assert!(adapter.is_filtered());
257 }
258}