1use crate::{
2 adapter::{Adapter, Filter},
3 convert::{EnforceArgs, TryIntoAdapter, TryIntoModel},
4 core_api::CoreApi,
5 effector::{DefaultEffector, EffectKind, Effector},
6 emitter::{Event, EventData, EventEmitter},
7 error::{ModelError, PolicyError, RequestError},
8 get_or_err, get_or_err_with_context,
9 management_api::MgmtApi,
10 model::{FunctionMap, Model, OperatorFunction},
11 rbac::{DefaultRoleManager, RoleManager},
12 register_g_function,
13 util::{escape_assertion, escape_eval},
14 Result,
15};
16
17#[cfg(any(feature = "logging", feature = "watcher"))]
18use crate::emitter::notify_logger_and_watcher;
19
20#[cfg(feature = "watcher")]
21use crate::watcher::Watcher;
22
23#[cfg(feature = "logging")]
24use crate::{DefaultLogger, Logger};
25
26use async_trait::async_trait;
27use once_cell::sync::Lazy;
28use parking_lot::RwLock;
29use rhai::{
30 def_package,
31 packages::{
32 ArithmeticPackage, BasicArrayPackage, BasicMapPackage, LogicPackage,
33 Package,
34 },
35 Dynamic, Engine, EvalAltResult, ImmutableString, Scope,
36};
37
38def_package! {
39 pub CasbinPackage(lib) {
40 ArithmeticPackage::init(lib);
41 LogicPackage::init(lib);
42 BasicArrayPackage::init(lib);
43 BasicMapPackage::init(lib);
44
45 lib.set_native_fn("escape_assertion", |s: ImmutableString| {
46 Ok(escape_assertion(&s))
47 });
48 }
49}
50
51static CASBIN_PACKAGE: Lazy<CasbinPackage> = Lazy::new(CasbinPackage::new);
52
53use std::{cmp::max, collections::HashMap, sync::Arc};
54
55type EventCallback = fn(&mut Enforcer, EventData);
56
57pub struct Enforcer {
59 model: Box<dyn Model>,
60 adapter: Box<dyn Adapter>,
61 fm: FunctionMap,
62 eft: Box<dyn Effector>,
63 rm: Arc<RwLock<dyn RoleManager>>,
64 enabled: bool,
65 auto_save: bool,
66 auto_build_role_links: bool,
67 #[cfg(feature = "watcher")]
68 auto_notify_watcher: bool,
69 #[cfg(feature = "watcher")]
70 watcher: Option<Box<dyn Watcher>>,
71 events: HashMap<Event, Vec<EventCallback>>,
72 engine: Engine,
73 #[cfg(feature = "logging")]
74 logger: Box<dyn Logger>,
75}
76
77pub struct EnforceContext {
78 pub r_type: String,
79 pub p_type: String,
80 pub e_type: String,
81 pub m_type: String,
82}
83
84impl EnforceContext {
85 pub fn new(suffix: &str) -> Self {
86 Self {
87 r_type: format!("r{}", suffix),
88 p_type: format!("p{}", suffix),
89 e_type: format!("e{}", suffix),
90 m_type: format!("m{}", suffix),
91 }
92 }
93 pub fn get_cache_key(&self) -> String {
94 format!(
95 "EnforceContext{{{}-{}-{}-{}}}",
96 &self.r_type, &self.p_type, &self.e_type, &self.m_type,
97 )
98 }
99}
100
101impl EventEmitter<Event> for Enforcer {
102 fn on(&mut self, e: Event, f: fn(&mut Self, EventData)) {
103 self.events.entry(e).or_default().push(f)
104 }
105
106 fn off(&mut self, e: Event) {
107 self.events.remove(&e);
108 }
109
110 fn emit(&mut self, e: Event, d: EventData) {
111 if let Some(cbs) = self.events.get(&e) {
112 for cb in cbs.clone().iter() {
113 cb(self, d.clone())
114 }
115 }
116 }
117}
118
119impl Enforcer {
120 pub(crate) fn private_enforce(
121 &self,
122 rvals: &[Dynamic],
123 ) -> Result<(bool, Option<Vec<usize>>)> {
124 if !self.enabled {
125 return Ok((true, None));
126 }
127
128 let mut scope: Scope = Scope::new();
129
130 let r_ast = get_or_err!(self, "r", ModelError::R, "request");
131 let p_ast = get_or_err!(self, "p", ModelError::P, "policy");
132 let m_ast = get_or_err!(self, "m", ModelError::M, "matcher");
133 let e_ast = get_or_err!(self, "e", ModelError::E, "effector");
134
135 if r_ast.tokens.len() != rvals.len() {
136 return Err(RequestError::UnmatchRequestDefinition(
137 r_ast.tokens.len(),
138 rvals.len(),
139 )
140 .into());
141 }
142
143 for (rtoken, rval) in r_ast.tokens.iter().zip(rvals.iter()) {
144 scope.push_constant_dynamic(rtoken, rval.to_owned());
145 }
146
147 let policies = p_ast.get_policy();
148 let (policy_len, scope_len) = (policies.len(), scope.len());
149
150 let mut eft_stream =
151 self.eft.new_stream(&e_ast.value, max(policy_len, 1));
152 let m_ast_compiled = self
153 .engine
154 .compile_expression(escape_eval(&m_ast.value))
155 .map_err(Into::<Box<EvalAltResult>>::into)?;
156
157 if policy_len == 0 {
158 for token in p_ast.tokens.iter() {
159 scope.push_constant(token, String::new());
160 }
161
162 let eval_result = self
163 .engine
164 .eval_ast_with_scope::<bool>(&mut scope, &m_ast_compiled)?;
165 let eft = if eval_result {
166 EffectKind::Allow
167 } else {
168 EffectKind::Indeterminate
169 };
170
171 eft_stream.push_effect(eft);
172
173 return Ok((eft_stream.next(), None));
174 }
175
176 for pvals in policies {
177 scope.rewind(scope_len);
178
179 if p_ast.tokens.len() != pvals.len() {
180 return Err(PolicyError::UnmatchPolicyDefinition(
181 p_ast.tokens.len(),
182 pvals.len(),
183 )
184 .into());
185 }
186 for (ptoken, pval) in p_ast.tokens.iter().zip(pvals.iter()) {
187 scope.push_constant(ptoken, pval.to_owned());
188 }
189
190 let eval_result = self
191 .engine
192 .eval_ast_with_scope::<bool>(&mut scope, &m_ast_compiled)?;
193 let eft = match p_ast.tokens.iter().position(|x| x == "p_eft") {
194 Some(j) if eval_result => {
195 let p_eft = &pvals[j];
196 if p_eft == "deny" {
197 EffectKind::Deny
198 } else if p_eft == "allow" {
199 EffectKind::Allow
200 } else {
201 EffectKind::Indeterminate
202 }
203 }
204 None if eval_result => EffectKind::Allow,
205 _ => EffectKind::Indeterminate,
206 };
207
208 if eft_stream.push_effect(eft) {
209 break;
210 }
211 }
212
213 Ok((eft_stream.next(), {
214 #[cfg(feature = "explain")]
215 {
216 eft_stream.explain()
217 }
218 #[cfg(not(feature = "explain"))]
219 {
220 None
221 }
222 }))
223 }
224
225 pub(crate) fn private_enforce_with_context(
226 &self,
227 ctx: EnforceContext,
228 rvals: &[Dynamic],
229 ) -> Result<(bool, Option<Vec<usize>>)> {
230 if !self.enabled {
231 return Ok((true, None));
232 }
233
234 let mut scope: Scope = Scope::new();
235 let r_ast = get_or_err_with_context!(
236 self,
237 "r",
238 &ctx.r_type,
239 ModelError::R,
240 "request"
241 );
242 let p_ast = get_or_err_with_context!(
243 self,
244 "p",
245 &ctx.p_type,
246 ModelError::P,
247 "policy"
248 );
249 let m_ast = get_or_err_with_context!(
250 self,
251 "m",
252 &ctx.m_type,
253 ModelError::M,
254 "matcher"
255 );
256 let e_ast = get_or_err_with_context!(
257 self,
258 "e",
259 &ctx.e_type,
260 ModelError::E,
261 "effector"
262 );
263
264 if r_ast.tokens.len() != rvals.len() {
265 return Err(RequestError::UnmatchRequestDefinition(
266 r_ast.tokens.len(),
267 rvals.len(),
268 )
269 .into());
270 }
271
272 for (rtoken, rval) in r_ast.tokens.iter().zip(rvals.iter()) {
273 scope.push_constant_dynamic(rtoken, rval.to_owned());
274 }
275
276 let policies = p_ast.get_policy();
277 let (policy_len, scope_len) = (policies.len(), scope.len());
278
279 let mut eft_stream =
280 self.eft.new_stream(&e_ast.value, max(policy_len, 1));
281 let m_ast_compiled = self
282 .engine
283 .compile_expression(escape_eval(&m_ast.value))
284 .map_err(Into::<Box<EvalAltResult>>::into)?;
285
286 if policy_len == 0 {
287 for token in p_ast.tokens.iter() {
288 scope.push_constant(token, String::new());
289 }
290
291 let eval_result = self
292 .engine
293 .eval_ast_with_scope::<bool>(&mut scope, &m_ast_compiled)?;
294 let eft = if eval_result {
295 EffectKind::Allow
296 } else {
297 EffectKind::Indeterminate
298 };
299
300 eft_stream.push_effect(eft);
301
302 return Ok((eft_stream.next(), None));
303 }
304
305 for pvals in policies {
306 scope.rewind(scope_len);
307
308 if p_ast.tokens.len() != pvals.len() {
309 return Err(PolicyError::UnmatchPolicyDefinition(
310 p_ast.tokens.len(),
311 pvals.len(),
312 )
313 .into());
314 }
315 for (ptoken, pval) in p_ast.tokens.iter().zip(pvals.iter()) {
316 scope.push_constant(ptoken, pval.to_owned());
317 }
318
319 let eval_result = self
320 .engine
321 .eval_ast_with_scope::<bool>(&mut scope, &m_ast_compiled)?;
322 let eft = match p_ast.tokens.iter().position(|x| x == "p_eft") {
323 Some(j) if eval_result => {
324 let p_eft = &pvals[j];
325 if p_eft == "deny" {
326 EffectKind::Deny
327 } else if p_eft == "allow" {
328 EffectKind::Allow
329 } else {
330 EffectKind::Indeterminate
331 }
332 }
333 None if eval_result => EffectKind::Allow,
334 _ => EffectKind::Indeterminate,
335 };
336
337 if eft_stream.push_effect(eft) {
338 break;
339 }
340 }
341
342 Ok((eft_stream.next(), {
343 #[cfg(feature = "explain")]
344 {
345 eft_stream.explain()
346 }
347 #[cfg(not(feature = "explain"))]
348 {
349 None
350 }
351 }))
352 }
353
354 fn register_function(engine: &mut Engine, key: &str, f: OperatorFunction) {
355 match f {
356 OperatorFunction::Arg0(func) => {
357 engine.register_fn(key, func);
358 }
359 OperatorFunction::Arg1(func) => {
360 engine.register_fn(key, func);
361 }
362 OperatorFunction::Arg2(func) => {
363 engine.register_fn(key, func);
364 }
365 OperatorFunction::Arg3(func) => {
366 engine.register_fn(key, func);
367 }
368 OperatorFunction::Arg4(func) => {
369 engine.register_fn(key, func);
370 }
371 OperatorFunction::Arg5(func) => {
372 engine.register_fn(key, func);
373 }
374 OperatorFunction::Arg6(func) => {
375 engine.register_fn(key, func);
376 }
377 }
378 }
379
380 pub(crate) fn register_g_functions(&mut self) -> Result<()> {
381 if let Some(ast_map) = self.model.get_model().get("g") {
382 for (fname, ast) in ast_map {
383 register_g_function!(self, fname, ast);
384 }
385 }
386
387 Ok(())
388 }
389}
390
391#[async_trait]
392impl CoreApi for Enforcer {
393 #[allow(clippy::box_default)]
394 async fn new_raw<M: TryIntoModel, A: TryIntoAdapter>(
395 m: M,
396 a: A,
397 ) -> Result<Self> {
398 let model = m.try_into_model().await?;
399 let adapter = a.try_into_adapter().await?;
400 let fm = FunctionMap::default();
401 let eft = Box::new(DefaultEffector);
402 let rm = Arc::new(RwLock::new(DefaultRoleManager::new(10)));
403
404 let mut engine = Engine::new_raw();
405
406 engine.register_global_module(CASBIN_PACKAGE.as_shared_module());
407
408 for (key, &func) in fm.get_functions() {
409 Self::register_function(&mut engine, key, func);
410 }
411
412 let mut e = Self {
413 model,
414 adapter,
415 fm,
416 eft,
417 rm,
418 enabled: true,
419 auto_save: true,
420 auto_build_role_links: true,
421 #[cfg(feature = "watcher")]
422 auto_notify_watcher: true,
423 #[cfg(feature = "watcher")]
424 watcher: None,
425 events: HashMap::new(),
426 engine,
427 #[cfg(feature = "logging")]
428 logger: Box::new(DefaultLogger::default()),
429 };
430
431 #[cfg(any(feature = "logging", feature = "watcher"))]
432 e.on(Event::PolicyChange, notify_logger_and_watcher);
433
434 e.register_g_functions()?;
435
436 Ok(e)
437 }
438
439 #[inline]
440 async fn new<M: TryIntoModel, A: TryIntoAdapter>(
441 m: M,
442 a: A,
443 ) -> Result<Self> {
444 let mut e = Self::new_raw(m, a).await?;
445
446 if !e.adapter.is_filtered() {
448 e.load_policy().await?;
449 }
450 Ok(e)
451 }
452
453 #[inline]
454 fn add_function(&mut self, fname: &str, f: OperatorFunction) {
455 self.fm.add_function(fname, f);
456 Self::register_function(&mut self.engine, fname, f);
457 }
458
459 #[inline]
460 fn get_model(&self) -> &dyn Model {
461 &*self.model
462 }
463
464 #[inline]
465 fn get_mut_model(&mut self) -> &mut dyn Model {
466 &mut *self.model
467 }
468
469 #[inline]
470 fn get_adapter(&self) -> &dyn Adapter {
471 &*self.adapter
472 }
473
474 #[inline]
475 fn get_mut_adapter(&mut self) -> &mut dyn Adapter {
476 &mut *self.adapter
477 }
478
479 #[cfg(feature = "watcher")]
480 #[inline]
481 fn set_watcher(&mut self, w: Box<dyn Watcher>) {
482 self.watcher = Some(w);
483 }
484
485 #[cfg(feature = "logging")]
486 #[inline]
487 fn get_logger(&self) -> &dyn Logger {
488 &*self.logger
489 }
490
491 #[cfg(feature = "logging")]
492 #[inline]
493 fn set_logger(&mut self, l: Box<dyn Logger>) {
494 self.logger = l;
495 }
496
497 #[cfg(feature = "watcher")]
498 #[inline]
499 fn get_watcher(&self) -> Option<&dyn Watcher> {
500 if let Some(ref watcher) = self.watcher {
501 Some(&**watcher)
502 } else {
503 None
504 }
505 }
506
507 #[cfg(feature = "watcher")]
508 #[inline]
509 fn get_mut_watcher(&mut self) -> Option<&mut dyn Watcher> {
510 if let Some(ref mut watcher) = self.watcher {
511 Some(&mut **watcher)
512 } else {
513 None
514 }
515 }
516
517 #[inline]
518 fn get_role_manager(&self) -> Arc<RwLock<dyn RoleManager>> {
519 Arc::clone(&self.rm)
520 }
521
522 #[inline]
523 fn set_role_manager(
524 &mut self,
525 rm: Arc<RwLock<dyn RoleManager>>,
526 ) -> Result<()> {
527 self.rm = rm;
528 if self.auto_build_role_links {
529 self.build_role_links()?;
530 }
531
532 self.register_g_functions()
533 }
534
535 async fn set_model<M: TryIntoModel>(&mut self, m: M) -> Result<()> {
536 self.model = m.try_into_model().await?;
537 self.load_policy().await?;
538 Ok(())
539 }
540
541 async fn set_adapter<A: TryIntoAdapter>(&mut self, a: A) -> Result<()> {
542 self.adapter = a.try_into_adapter().await?;
543 self.load_policy().await?;
544 Ok(())
545 }
546
547 #[inline]
548 fn set_effector(&mut self, e: Box<dyn Effector>) {
549 self.eft = e;
550 }
551
552 fn enforce<ARGS: EnforceArgs>(&self, rvals: ARGS) -> Result<bool> {
578 let rvals = rvals.try_into_vec()?;
579 #[allow(unused_variables)]
580 let (authorized, indices) = self.private_enforce(&rvals)?;
581
582 #[cfg(feature = "logging")]
583 {
584 self.logger.print_enforce_log(
585 rvals.iter().map(|x| x.to_string()).collect(),
586 authorized,
587 false,
588 );
589
590 #[cfg(feature = "explain")]
591 if let Some(indices) = indices {
592 let all_rules = get_or_err!(self, "p", ModelError::P, "policy")
593 .get_policy();
594
595 let rules: Vec<String> = indices
596 .into_iter()
597 .filter_map(|y| {
598 all_rules.iter().nth(y).map(|x| x.join(", "))
599 })
600 .collect();
601
602 self.logger.print_explain_log(rules);
603 }
604 }
605
606 Ok(authorized)
607 }
608 fn enforce_with_context<ARGS: EnforceArgs>(
641 &self,
642 ctx: EnforceContext,
643 rvals: ARGS,
644 ) -> Result<bool> {
645 let rvals = rvals.try_into_vec()?;
646 #[allow(unused_variables)]
647 let (authorized, indices) =
648 self.private_enforce_with_context(ctx, &rvals)?;
649
650 #[cfg(feature = "logging")]
651 {
652 self.logger.print_enforce_log(
653 rvals.iter().map(|x| x.to_string()).collect(),
654 authorized,
655 false,
656 );
657
658 #[cfg(feature = "explain")]
659 if let Some(indices) = indices {
660 let all_rules = get_or_err!(self, "p", ModelError::P, "policy")
661 .get_policy();
662
663 let rules: Vec<String> = indices
664 .into_iter()
665 .filter_map(|y| {
666 all_rules.iter().nth(y).map(|x| x.join(", "))
667 })
668 .collect();
669
670 self.logger.print_explain_log(rules);
671 }
672 }
673
674 Ok(authorized)
675 }
676
677 fn enforce_mut<ARGS: EnforceArgs>(&mut self, rvals: ARGS) -> Result<bool> {
678 self.enforce(rvals)
679 }
680
681 #[cfg(feature = "explain")]
682 fn enforce_ex<ARGS: EnforceArgs>(
683 &self,
684 rvals: ARGS,
685 ) -> Result<(bool, Vec<Vec<String>>)> {
686 let rvals = rvals.try_into_vec()?;
687 #[allow(unused_variables)]
688 let (authorized, indices) = self.private_enforce(&rvals)?;
689
690 let rules = match indices {
691 Some(indices) => {
692 let all_rules = get_or_err!(self, "p", ModelError::P, "policy")
693 .get_policy();
694
695 indices
696 .into_iter()
697 .filter_map(|y| all_rules.iter().nth(y).cloned())
698 .collect::<Vec<_>>()
699 }
700 None => vec![],
701 };
702
703 Ok((authorized, rules))
704 }
705
706 fn build_role_links(&mut self) -> Result<()> {
707 self.rm.write().clear();
708 self.model.build_role_links(Arc::clone(&self.rm))?;
709
710 Ok(())
711 }
712
713 #[cfg(feature = "incremental")]
714 fn build_incremental_role_links(&mut self, d: EventData) -> Result<()> {
715 self.model
716 .build_incremental_role_links(Arc::clone(&self.rm), d)?;
717
718 Ok(())
719 }
720
721 async fn load_policy(&mut self) -> Result<()> {
722 self.model.clear_policy();
723 self.adapter.load_policy(&mut *self.model).await?;
724
725 if self.auto_build_role_links {
726 self.build_role_links()?;
727 }
728
729 Ok(())
730 }
731
732 async fn load_filtered_policy<'a>(&mut self, f: Filter<'a>) -> Result<()> {
733 self.model.clear_policy();
734 self.adapter
735 .load_filtered_policy(&mut *self.model, f)
736 .await?;
737
738 if self.auto_build_role_links {
739 self.build_role_links()?;
740 }
741
742 Ok(())
743 }
744
745 #[inline]
746 fn is_filtered(&self) -> bool {
747 self.adapter.is_filtered()
748 }
749
750 #[inline]
751 fn is_enabled(&self) -> bool {
752 self.enabled
753 }
754
755 async fn save_policy(&mut self) -> Result<()> {
756 assert!(!self.is_filtered(), "cannot save filtered policy");
757
758 self.adapter.save_policy(&mut *self.model).await?;
759
760 let mut policies = self.get_all_policy();
761 let gpolicies = self.get_all_grouping_policy();
762
763 policies.extend(gpolicies);
764
765 #[cfg(any(feature = "logging", feature = "watcher"))]
766 self.emit(Event::PolicyChange, EventData::SavePolicy(policies));
767
768 Ok(())
769 }
770
771 #[inline]
772 async fn clear_policy(&mut self) -> Result<()> {
773 if self.auto_save {
774 self.adapter.clear_policy().await?;
775 }
776 self.model.clear_policy();
777
778 #[cfg(any(feature = "logging", feature = "watcher"))]
779 self.emit(Event::PolicyChange, EventData::ClearPolicy);
780
781 Ok(())
782 }
783
784 #[inline]
785 fn enable_enforce(&mut self, enabled: bool) {
786 self.enabled = enabled;
787
788 #[cfg(feature = "logging")]
789 self.logger.print_status_log(enabled);
790 }
791
792 #[cfg(feature = "logging")]
793 #[inline]
794 fn enable_log(&mut self, enabled: bool) {
795 self.logger.enable_log(enabled);
796 }
797
798 #[inline]
799 fn enable_auto_save(&mut self, auto_save: bool) {
800 self.auto_save = auto_save;
801 }
802
803 #[inline]
804 fn enable_auto_build_role_links(&mut self, auto_build_role_links: bool) {
805 self.auto_build_role_links = auto_build_role_links;
806 }
807
808 #[cfg(feature = "watcher")]
809 #[inline]
810 fn enable_auto_notify_watcher(&mut self, auto_notify_watcher: bool) {
811 if !auto_notify_watcher {
812 self.off(Event::PolicyChange);
813 } else {
814 self.on(Event::PolicyChange, notify_logger_and_watcher);
815 }
816
817 self.auto_notify_watcher = auto_notify_watcher;
818 }
819
820 #[inline]
821 fn has_auto_save_enabled(&self) -> bool {
822 self.auto_save
823 }
824
825 #[cfg(feature = "watcher")]
826 #[inline]
827 fn has_auto_notify_watcher_enabled(&self) -> bool {
828 self.auto_notify_watcher
829 }
830
831 #[inline]
832 fn has_auto_build_role_links_enabled(&self) -> bool {
833 self.auto_build_role_links
834 }
835}
836
837#[cfg(test)]
838mod tests {
839 use super::*;
840 use crate::prelude::*;
841
842 fn is_send<T: Send>() -> bool {
843 true
844 }
845
846 fn is_sync<T: Sync>() -> bool {
847 true
848 }
849
850 #[test]
851 fn test_send_sync() {
852 assert!(is_send::<Enforcer>());
853 assert!(is_sync::<Enforcer>());
854 }
855
856 #[cfg(not(target_arch = "wasm32"))]
857 #[cfg_attr(
858 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
859 async_std::test
860 )]
861 #[cfg_attr(
862 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
863 tokio::test
864 )]
865 async fn test_enforcer_swap_adapter_type() {
866 let mut m = DefaultModel::default();
867 m.add_def("r", "r", "sub, obj, act");
868 m.add_def("p", "p", "sub, obj, act");
869 m.add_def("e", "e", "some(where (p.eft == allow))");
870 m.add_def(
871 "m",
872 "m",
873 "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)",
874 );
875
876 let file = FileAdapter::new("examples/basic_policy.csv");
877 let mem = MemoryAdapter::default();
878 let mut e = Enforcer::new(m, file).await.unwrap();
879 assert!(e
881 .adapter
882 .add_policy(
883 "p",
884 "p",
885 vec!["alice".into(), "data".into(), "read".into()]
886 )
887 .await
888 .unwrap());
889 e.set_adapter(mem).await.unwrap();
890 assert!(e
892 .adapter
893 .add_policy(
894 "p",
895 "p",
896 vec!["alice".into(), "data".into(), "read".into()]
897 )
898 .await
899 .unwrap())
900 }
901
902 #[cfg(not(target_arch = "wasm32"))]
903 #[cfg_attr(
904 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
905 async_std::test
906 )]
907 #[cfg_attr(
908 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
909 tokio::test
910 )]
911 async fn test_key_match_model_in_memory() {
912 let mut m = DefaultModel::default();
913 m.add_def("r", "r", "sub, obj, act");
914 m.add_def("p", "p", "sub, obj, act");
915 m.add_def("e", "e", "some(where (p.eft == allow))");
916 m.add_def(
917 "m",
918 "m",
919 "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)",
920 );
921
922 let adapter = FileAdapter::new("examples/keymatch_policy.csv");
923 let e = Enforcer::new(m, adapter).await.unwrap();
924 assert_eq!(
925 true,
926 e.enforce(("alice", "/alice_data/resource1", "GET"))
927 .unwrap()
928 );
929 assert_eq!(
930 true,
931 e.enforce(("alice", "/alice_data/resource1", "POST"))
932 .unwrap()
933 );
934 assert_eq!(
935 true,
936 e.enforce(("alice", "/alice_data/resource2", "GET"))
937 .unwrap()
938 );
939 assert_eq!(
940 false,
941 e.enforce(("alice", "/alice_data/resource2", "POST"))
942 .unwrap()
943 );
944 assert_eq!(
945 false,
946 e.enforce(("alice", "/bob_data/resource1", "GET")).unwrap()
947 );
948 assert_eq!(
949 false,
950 e.enforce(("alice", "/bob_data/resource1", "POST")).unwrap()
951 );
952 assert_eq!(
953 false,
954 e.enforce(("alice", "/bob_data/resource2", "GET")).unwrap()
955 );
956 assert_eq!(
957 false,
958 e.enforce(("alice", "/bob_data/resource2", "POST")).unwrap()
959 );
960
961 assert_eq!(
962 false,
963 e.enforce(("bob", "/alice_data/resource1", "GET")).unwrap()
964 );
965 assert_eq!(
966 false,
967 e.enforce(("bob", "/alice_data/resource1", "POST")).unwrap()
968 );
969 assert_eq!(
970 true,
971 e.enforce(("bob", "/alice_data/resource2", "GET")).unwrap()
972 );
973 assert_eq!(
974 false,
975 e.enforce(("bob", "/alice_data/resource2", "POST")).unwrap()
976 );
977 assert_eq!(
978 false,
979 e.enforce(("bob", "/bob_data/resource1", "GET")).unwrap()
980 );
981 assert_eq!(
982 true,
983 e.enforce(("bob", "/bob_data/resource1", "POST")).unwrap()
984 );
985 assert_eq!(
986 false,
987 e.enforce(("bob", "/bob_data/resource2", "GET")).unwrap()
988 );
989 assert_eq!(
990 true,
991 e.enforce(("bob", "/bob_data/resource2", "POST")).unwrap()
992 );
993
994 assert_eq!(true, e.enforce(("cathy", "/cathy_data", "GET")).unwrap());
995 assert_eq!(true, e.enforce(("cathy", "/cathy_data", "POST")).unwrap());
996 assert_eq!(
997 false,
998 e.enforce(("cathy", "/cathy_data", "DELETE")).unwrap()
999 );
1000 }
1001
1002 #[cfg(not(target_arch = "wasm32"))]
1003 #[cfg_attr(
1004 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
1005 async_std::test
1006 )]
1007 #[cfg_attr(
1008 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
1009 tokio::test
1010 )]
1011 async fn test_key_match_model_in_memory_deny() {
1012 let mut m = DefaultModel::default();
1013 m.add_def("r", "r", "sub, obj, act");
1014 m.add_def("p", "p", "sub, obj, act");
1015 m.add_def("e", "e", "!some(where (p.eft == deny))");
1016 m.add_def(
1017 "m",
1018 "m",
1019 "r.sub == p.sub && keyMatch(r.obj, p.obj) && regexMatch(r.act, p.act)",
1020 );
1021
1022 let adapter = FileAdapter::new("examples/keymatch_policy.csv");
1023 let e = Enforcer::new(m, adapter).await.unwrap();
1024 assert_eq!(
1025 true,
1026 e.enforce(("alice", "/alice_data/resource2", "POST"))
1027 .unwrap()
1028 );
1029 }
1030
1031 use crate::RbacApi;
1032 #[cfg(not(target_arch = "wasm32"))]
1033 #[cfg_attr(
1034 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
1035 async_std::test
1036 )]
1037 #[cfg_attr(
1038 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
1039 tokio::test
1040 )]
1041 async fn test_rbac_model_in_memory_indeterminate() {
1042 let mut m = DefaultModel::default();
1043 m.add_def("r", "r", "sub, obj, act");
1044 m.add_def("p", "p", "sub, obj, act");
1045 m.add_def("g", "g", "_, _");
1046 m.add_def("e", "e", "some(where (p.eft == allow))");
1047 m.add_def(
1048 "m",
1049 "m",
1050 "g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act",
1051 );
1052
1053 let adapter = MemoryAdapter::default();
1054 let mut e = Enforcer::new(m, adapter).await.unwrap();
1055 e.add_permission_for_user(
1056 "alice",
1057 vec!["data1", "invalid"]
1058 .iter()
1059 .map(|s| s.to_string())
1060 .collect(),
1061 )
1062 .await
1063 .unwrap();
1064 assert_eq!(false, e.enforce(("alice", "data1", "read")).unwrap());
1065 }
1066
1067 #[cfg(not(target_arch = "wasm32"))]
1068 #[cfg_attr(
1069 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
1070 async_std::test
1071 )]
1072 #[cfg_attr(
1073 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
1074 tokio::test
1075 )]
1076 async fn test_rbac_model_in_memory() {
1077 let mut m = DefaultModel::default();
1078 m.add_def("r", "r", "sub, obj, act");
1079 m.add_def("p", "p", "sub, obj, act");
1080 m.add_def("g", "g", "_, _");
1081 m.add_def("e", "e", "some(where (p.eft == allow))");
1082 m.add_def(
1083 "m",
1084 "m",
1085 "g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act",
1086 );
1087
1088 let adapter = MemoryAdapter::default();
1089 let mut e = Enforcer::new(m, adapter).await.unwrap();
1090 e.add_permission_for_user(
1091 "alice",
1092 vec!["data1", "read"]
1093 .iter()
1094 .map(|s| s.to_string())
1095 .collect(),
1096 )
1097 .await
1098 .unwrap();
1099 e.add_permission_for_user(
1100 "bob",
1101 vec!["data2", "write"]
1102 .iter()
1103 .map(|s| s.to_string())
1104 .collect(),
1105 )
1106 .await
1107 .unwrap();
1108 e.add_permission_for_user(
1109 "data2_admin",
1110 vec!["data2", "read"]
1111 .iter()
1112 .map(|s| s.to_string())
1113 .collect(),
1114 )
1115 .await
1116 .unwrap();
1117 e.add_permission_for_user(
1118 "data2_admin",
1119 vec!["data2", "write"]
1120 .iter()
1121 .map(|s| s.to_string())
1122 .collect(),
1123 )
1124 .await
1125 .unwrap();
1126 e.add_role_for_user("alice", "data2_admin", None)
1127 .await
1128 .unwrap();
1129
1130 assert_eq!(true, e.enforce(("alice", "data1", "read")).unwrap());
1131 assert_eq!(false, e.enforce(("alice", "data1", "write")).unwrap());
1132 assert_eq!(true, e.enforce(("alice", "data2", "read")).unwrap());
1133 assert_eq!(true, e.enforce(("alice", "data2", "write")).unwrap());
1134 assert_eq!(false, e.enforce(("bob", "data1", "read")).unwrap());
1135 assert_eq!(false, e.enforce(("bob", "data1", "write")).unwrap());
1136 assert_eq!(false, e.enforce(("bob", "data2", "read")).unwrap());
1137 assert_eq!(true, e.enforce(("bob", "data2", "write")).unwrap());
1138 }
1139
1140 #[cfg(not(target_arch = "wasm32"))]
1141 #[cfg_attr(
1142 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
1143 async_std::test
1144 )]
1145 #[cfg_attr(
1146 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
1147 tokio::test
1148 )]
1149 async fn test_not_used_rbac_model_in_memory() {
1150 let mut m = DefaultModel::default();
1151 m.add_def("r", "r", "sub, obj, act");
1152 m.add_def("p", "p", "sub, obj, act");
1153 m.add_def("g", "g", "_, _");
1154 m.add_def("e", "e", "some(where (p.eft == allow))");
1155 m.add_def(
1156 "m",
1157 "m",
1158 "g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act",
1159 );
1160
1161 let adapter = MemoryAdapter::default();
1162 let mut e = Enforcer::new(m, adapter).await.unwrap();
1163 e.add_permission_for_user(
1164 "alice",
1165 vec!["data1", "read"]
1166 .iter()
1167 .map(|s| s.to_string())
1168 .collect(),
1169 )
1170 .await
1171 .unwrap();
1172 e.add_permission_for_user(
1173 "bob",
1174 vec!["data2", "write"]
1175 .iter()
1176 .map(|s| s.to_string())
1177 .collect(),
1178 )
1179 .await
1180 .unwrap();
1181
1182 assert_eq!(true, e.enforce(("alice", "data1", "read")).unwrap());
1183 assert_eq!(false, e.enforce(("alice", "data1", "write")).unwrap());
1184 assert_eq!(false, e.enforce(("alice", "data2", "read")).unwrap());
1185 assert_eq!(false, e.enforce(("alice", "data2", "write")).unwrap());
1186 assert_eq!(false, e.enforce(("bob", "data1", "read")).unwrap());
1187 assert_eq!(false, e.enforce(("bob", "data1", "write")).unwrap());
1188 assert_eq!(false, e.enforce(("bob", "data2", "read")).unwrap());
1189 assert_eq!(true, e.enforce(("bob", "data2", "write")).unwrap());
1190 }
1191
1192 #[cfg(feature = "ip")]
1193 #[cfg(not(target_arch = "wasm32"))]
1194 #[cfg_attr(
1195 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
1196 async_std::test
1197 )]
1198 #[cfg_attr(
1199 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
1200 tokio::test
1201 )]
1202 async fn test_ip_match_model() {
1203 let m = DefaultModel::from_file("examples/ipmatch_model.conf")
1204 .await
1205 .unwrap();
1206
1207 let adapter = FileAdapter::new("examples/ipmatch_policy.csv");
1208 let e = Enforcer::new(m, adapter).await.unwrap();
1209
1210 assert!(e.enforce(("192.168.2.123", "data1", "read")).unwrap());
1211
1212 assert!(e.enforce(("10.0.0.5", "data2", "write")).unwrap());
1213
1214 assert!(!e.enforce(("192.168.2.123", "data1", "write")).unwrap());
1215 assert!(!e.enforce(("192.168.2.123", "data2", "read")).unwrap());
1216 assert!(!e.enforce(("192.168.2.123", "data2", "write")).unwrap());
1217
1218 assert!(!e.enforce(("192.168.0.123", "data1", "read")).unwrap());
1219 assert!(!e.enforce(("192.168.0.123", "data1", "write")).unwrap());
1220 assert!(!e.enforce(("192.168.0.123", "data2", "read")).unwrap());
1221 assert!(!e.enforce(("192.168.0.123", "data2", "write")).unwrap());
1222
1223 assert!(!e.enforce(("10.0.0.5", "data1", "read")).unwrap());
1224 assert!(!e.enforce(("10.0.0.5", "data1", "write")).unwrap());
1225 assert!(!e.enforce(("10.0.0.5", "data2", "read")).unwrap());
1226
1227 assert!(!e.enforce(("192.168.0.1", "data1", "read")).unwrap());
1228 assert!(!e.enforce(("192.168.0.1", "data1", "write")).unwrap());
1229 assert!(!e.enforce(("192.168.0.1", "data2", "read")).unwrap());
1230 assert!(!e.enforce(("192.168.0.1", "data2", "write")).unwrap());
1231 }
1232
1233 #[cfg(not(target_arch = "wasm32"))]
1234 #[cfg_attr(
1235 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
1236 async_std::test
1237 )]
1238 #[cfg_attr(
1239 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
1240 tokio::test
1241 )]
1242 async fn test_enable_auto_save() {
1243 let m = DefaultModel::from_file("examples/basic_model.conf")
1244 .await
1245 .unwrap();
1246
1247 let adapter = FileAdapter::new("examples/basic_policy.csv");
1248 let mut e = Enforcer::new(m, adapter).await.unwrap();
1249 e.enable_auto_save(false);
1250 e.remove_policy(
1251 vec!["alice", "data1", "read"]
1252 .iter()
1253 .map(|s| s.to_string())
1254 .collect(),
1255 )
1256 .await
1257 .unwrap();
1258 e.load_policy().await.unwrap();
1259
1260 assert_eq!(true, e.enforce(("alice", "data1", "read")).unwrap());
1261 assert_eq!(false, e.enforce(("alice", "data1", "write")).unwrap());
1262 assert_eq!(false, e.enforce(("alice", "data2", "read")).unwrap());
1263 assert_eq!(false, e.enforce(("alice", "data2", "write")).unwrap());
1264 assert_eq!(false, e.enforce(("bob", "data1", "read")).unwrap());
1265 assert_eq!(false, e.enforce(("bob", "data1", "write")).unwrap());
1266 assert_eq!(false, e.enforce(("bob", "data2", "read")).unwrap());
1267 assert_eq!(true, e.enforce(("bob", "data2", "write")).unwrap());
1268
1269 e.enable_auto_save(true);
1270 e.remove_policy(
1271 vec!["alice", "data1", "read"]
1272 .iter()
1273 .map(|s| s.to_string())
1274 .collect(),
1275 )
1276 .await
1277 .unwrap();
1278 e.load_policy().await.unwrap();
1279 assert_eq!(true, e.enforce(("alice", "data1", "read")).unwrap());
1280 assert_eq!(false, e.enforce(("alice", "data1", "write")).unwrap());
1281 assert_eq!(false, e.enforce(("alice", "data2", "read")).unwrap());
1282 assert_eq!(false, e.enforce(("alice", "data2", "write")).unwrap());
1283 assert_eq!(false, e.enforce(("bob", "data1", "read")).unwrap());
1284 assert_eq!(false, e.enforce(("bob", "data1", "write")).unwrap());
1285 assert_eq!(false, e.enforce(("bob", "data2", "read")).unwrap());
1286 assert_eq!(true, e.enforce(("bob", "data2", "write")).unwrap());
1287 }
1288
1289 #[cfg(not(target_arch = "wasm32"))]
1290 #[cfg_attr(
1291 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
1292 async_std::test
1293 )]
1294 #[cfg_attr(
1295 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
1296 tokio::test
1297 )]
1298 async fn test_role_links() {
1299 let m = DefaultModel::from_file("examples/rbac_model.conf")
1300 .await
1301 .unwrap();
1302
1303 let adapter = MemoryAdapter::default();
1304 let mut e = Enforcer::new(m, adapter).await.unwrap();
1305 e.enable_auto_build_role_links(false);
1306 e.build_role_links().unwrap();
1307 assert_eq!(false, e.enforce(("user501", "data9", "read")).unwrap());
1308 }
1309
1310 #[cfg(not(target_arch = "wasm32"))]
1311 #[cfg_attr(
1312 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
1313 async_std::test
1314 )]
1315 #[cfg_attr(
1316 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
1317 tokio::test
1318 )]
1319 async fn test_get_and_set_model() {
1320 let m1 = DefaultModel::from_file("examples/basic_model.conf")
1321 .await
1322 .unwrap();
1323 let adapter1 = FileAdapter::new("examples/basic_policy.csv");
1324 let mut e = Enforcer::new(m1, adapter1).await.unwrap();
1325
1326 assert_eq!(false, e.enforce(("root", "data1", "read")).unwrap());
1327
1328 let m2 = DefaultModel::from_file("examples/basic_with_root_model.conf")
1329 .await
1330 .unwrap();
1331 let adapter2 = FileAdapter::new("examples/basic_policy.csv");
1332 let e2 = Enforcer::new(m2, adapter2).await.unwrap();
1333
1334 e.model = e2.model;
1335 assert_eq!(true, e.enforce(("root", "data1", "read")).unwrap());
1336 }
1337
1338 #[cfg(not(target_arch = "wasm32"))]
1339 #[cfg_attr(
1340 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
1341 async_std::test
1342 )]
1343 #[cfg_attr(
1344 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
1345 tokio::test
1346 )]
1347 async fn test_get_and_set_adapter_in_mem() {
1348 let m1 = DefaultModel::from_file("examples/basic_model.conf")
1349 .await
1350 .unwrap();
1351 let adapter1 = FileAdapter::new("examples/basic_policy.csv");
1352 let mut e = Enforcer::new(m1, adapter1).await.unwrap();
1353
1354 assert_eq!(true, e.enforce(("alice", "data1", "read")).unwrap());
1355 assert_eq!(false, e.enforce(("alice", "data1", "write")).unwrap());
1356
1357 let m2 = DefaultModel::from_file("examples/basic_model.conf")
1358 .await
1359 .unwrap();
1360 let adapter2 = FileAdapter::new("examples/basic_inverse_policy.csv");
1361 let e2 = Enforcer::new(m2, adapter2).await.unwrap();
1362
1363 e.adapter = e2.adapter;
1364 e.load_policy().await.unwrap();
1365 assert_eq!(false, e.enforce(("alice", "data1", "read")).unwrap());
1366 assert_eq!(true, e.enforce(("alice", "data1", "write")).unwrap());
1367 }
1368
1369 #[cfg(not(target_arch = "wasm32"))]
1370 #[cfg_attr(
1371 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
1372 async_std::test
1373 )]
1374 #[cfg_attr(
1375 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
1376 tokio::test
1377 )]
1378 async fn test_keymatch_custom_model() {
1379 use crate::model::key_match;
1380
1381 let m1 = DefaultModel::from_file("examples/keymatch_custom_model.conf")
1382 .await
1383 .unwrap();
1384 let adapter1 = FileAdapter::new("examples/keymatch_policy.csv");
1385 let mut e = Enforcer::new(m1, adapter1).await.unwrap();
1386
1387 e.add_function(
1388 "keyMatchCustom",
1389 OperatorFunction::Arg2(
1390 |s1: ImmutableString, s2: ImmutableString| {
1391 key_match(&s1, &s2).into()
1392 },
1393 ),
1394 );
1395
1396 assert_eq!(
1397 true,
1398 e.enforce(("alice", "/alice_data/123", "GET")).unwrap()
1399 );
1400 assert_eq!(
1401 true,
1402 e.enforce(("alice", "/alice_data/resource1", "POST"))
1403 .unwrap()
1404 );
1405
1406 assert_eq!(
1407 true,
1408 e.enforce(("bob", "/alice_data/resource2", "GET")).unwrap()
1409 );
1410
1411 assert_eq!(
1412 true,
1413 e.enforce(("bob", "/bob_data/resource1", "POST")).unwrap()
1414 );
1415
1416 assert_eq!(true, e.enforce(("cathy", "/cathy_data", "GET")).unwrap());
1417 assert_eq!(true, e.enforce(("cathy", "/cathy_data", "POST")).unwrap());
1418 }
1419
1420 #[cfg(not(target_arch = "wasm32"))]
1421 #[cfg_attr(
1422 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
1423 async_std::test
1424 )]
1425 #[cfg_attr(
1426 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
1427 tokio::test
1428 )]
1429 async fn test_filtered_file_adapter() {
1430 let adapter = FileAdapter::new_filtered_adapter(
1431 "examples/rbac_with_domains_policy.csv",
1432 );
1433 let mut e =
1434 Enforcer::new("examples/rbac_with_domains_model.conf", adapter)
1435 .await
1436 .unwrap();
1437
1438 let filter = Filter {
1439 p: vec!["", "domain1"],
1440 g: vec!["", "", "domain1"],
1441 };
1442
1443 e.load_filtered_policy(filter).await.unwrap();
1444 assert_eq!(
1445 e.enforce(("alice", "domain1", "data1", "read")).unwrap(),
1446 true
1447 );
1448 assert!(e.enforce(("alice", "domain1", "data1", "write")).unwrap());
1449 assert!(!e.enforce(("alice", "domain1", "data2", "read")).unwrap());
1450 assert!(!e.enforce(("alice", "domain1", "data2", "write")).unwrap());
1451 assert!(!e.enforce(("bob", "domain2", "data2", "read")).unwrap());
1452 assert!(!e.enforce(("bob", "domain2", "data2", "write")).unwrap());
1453 }
1454
1455 #[cfg(not(target_arch = "wasm32"))]
1456 #[cfg_attr(
1457 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
1458 async_std::test
1459 )]
1460 #[cfg_attr(
1461 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
1462 tokio::test
1463 )]
1464 async fn test_set_role_manager() {
1465 let mut e = Enforcer::new(
1466 "examples/rbac_with_domains_model.conf",
1467 "examples/rbac_with_domains_policy.csv",
1468 )
1469 .await
1470 .unwrap();
1471
1472 let new_rm = Arc::new(RwLock::new(DefaultRoleManager::new(10)));
1473
1474 e.set_role_manager(new_rm).unwrap();
1475
1476 assert!(e.enforce(("alice", "domain1", "data1", "read")).unwrap(),);
1477 assert!(e.enforce(("alice", "domain1", "data1", "write")).unwrap());
1478 assert!(e.enforce(("bob", "domain2", "data2", "read")).unwrap());
1479 assert!(e.enforce(("bob", "domain2", "data2", "write")).unwrap());
1480 }
1481
1482 #[cfg(not(target_arch = "wasm32"))]
1483 #[cfg_attr(
1484 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
1485 async_std::test
1486 )]
1487 #[cfg_attr(
1488 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
1489 tokio::test
1490 )]
1491 async fn test_policy_abac1() {
1492 use serde::Serialize;
1493
1494 let mut m = DefaultModel::default();
1495 m.add_def("r", "r", "sub, obj, act");
1496 m.add_def("p", "p", "sub_rule, obj, act");
1497 m.add_def("e", "e", "some(where (p.eft == allow))");
1498 m.add_def(
1499 "m",
1500 "m",
1501 "eval(p.sub_rule) && r.obj == p.obj && r.act == p.act",
1502 );
1503
1504 let a = MemoryAdapter::default();
1505
1506 let mut e = Enforcer::new(m, a).await.unwrap();
1507
1508 e.add_policy(
1509 vec!["r.sub.age > 18", "/data1", "read"]
1510 .into_iter()
1511 .map(|x| x.to_string())
1512 .collect(),
1513 )
1514 .await
1515 .unwrap();
1516
1517 #[derive(Serialize, Hash)]
1518 pub struct Person<'a> {
1519 name: &'a str,
1520 age: u8,
1521 }
1522
1523 assert_eq!(
1524 e.enforce((
1525 Person {
1526 name: "alice",
1527 age: 16
1528 },
1529 "/data1",
1530 "read"
1531 ))
1532 .unwrap(),
1533 false
1534 );
1535 assert_eq!(
1536 e.enforce((
1537 Person {
1538 name: "bob",
1539 age: 19
1540 },
1541 "/data1",
1542 "read"
1543 ))
1544 .unwrap(),
1545 true
1546 );
1547 }
1548
1549 #[cfg(not(target_arch = "wasm32"))]
1550 #[cfg_attr(
1551 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
1552 async_std::test
1553 )]
1554 #[cfg_attr(
1555 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
1556 tokio::test
1557 )]
1558 async fn test_policy_abac2() {
1559 use serde::Serialize;
1560
1561 let mut m = DefaultModel::default();
1562 m.add_def("r", "r", "sub, obj, act");
1563 m.add_def("p", "p", "sub, obj, act");
1564 m.add_def("e", "e", "some(where (p.eft == allow))");
1565 m.add_def("g", "g", "_, _");
1566 m.add_def(
1567 "m",
1568 "m",
1569 "(g(r.sub, p.sub) || eval(p.sub) == true) && r.act == p.act",
1570 );
1571
1572 let a = MemoryAdapter::default();
1573
1574 let mut e = Enforcer::new(m, a).await.unwrap();
1575
1576 e.add_policy(
1577 vec![r#""admin""#, "post", "write"]
1578 .into_iter()
1579 .map(|x| x.to_string())
1580 .collect(),
1581 )
1582 .await
1583 .unwrap();
1584
1585 e.add_policy(
1586 vec!["r.sub == r.obj.author", "post", "write"]
1587 .into_iter()
1588 .map(|x| x.to_string())
1589 .collect(),
1590 )
1591 .await
1592 .unwrap();
1593
1594 e.add_grouping_policy(
1595 vec!["alice", r#""admin""#]
1596 .into_iter()
1597 .map(|x| x.to_string())
1598 .collect(),
1599 )
1600 .await
1601 .unwrap();
1602
1603 #[derive(Serialize, Hash)]
1604 pub struct Post<'a> {
1605 author: &'a str,
1606 }
1607
1608 assert_eq!(
1609 e.enforce(("alice", Post { author: "bob" }, "write"))
1610 .unwrap(),
1611 true
1612 );
1613
1614 assert_eq!(
1615 e.enforce(("bob", Post { author: "bob" }, "write")).unwrap(),
1616 true
1617 );
1618 }
1619
1620 #[cfg(feature = "explain")]
1621 #[cfg(not(target_arch = "wasm32"))]
1622 #[cfg_attr(
1623 all(feature = "runtime-async-std", not(target_arch = "wasm32")),
1624 async_std::test
1625 )]
1626 #[cfg_attr(
1627 all(feature = "runtime-tokio", not(target_arch = "wasm32")),
1628 tokio::test
1629 )]
1630 async fn test_enforce_ex() {
1631 use crate::adapter;
1632
1633 let model = DefaultModel::from_file("examples/basic_model.conf")
1634 .await
1635 .unwrap();
1636
1637 let adapter = adapter::FileAdapter::new("examples/basic_policy.csv");
1638
1639 let e = Enforcer::new(model, adapter).await.unwrap();
1640
1641 assert_eq!(
1642 e.enforce_ex(("alice", "data1", "read")).unwrap(),
1643 (
1644 true,
1645 vec![vec![
1646 "alice".to_string(),
1647 "data1".to_string(),
1648 "read".to_string()
1649 ]]
1650 )
1651 );
1652 assert_eq!(
1653 e.enforce_ex(("alice", "data1", "write")).unwrap(),
1654 (false, vec![])
1655 );
1656 assert_eq!(
1657 e.enforce_ex(("alice", "data2", "read")).unwrap(),
1658 (false, vec![])
1659 );
1660 assert_eq!(
1661 e.enforce_ex(("alice", "data2", "write")).unwrap(),
1662 (false, vec![])
1663 );
1664 assert_eq!(
1665 e.enforce_ex(("bob", "data1", "read")).unwrap(),
1666 (false, vec![])
1667 );
1668 assert_eq!(
1669 e.enforce_ex(("bob", "data1", "write")).unwrap(),
1670 (false, vec![])
1671 );
1672 assert_eq!(
1673 e.enforce_ex(("bob", "data2", "read")).unwrap(),
1674 (false, vec![])
1675 );
1676 assert_eq!(
1677 e.enforce_ex(("bob", "data2", "write")).unwrap(),
1678 (
1679 true,
1680 vec![vec![
1681 "bob".to_string(),
1682 "data2".to_string(),
1683 "write".to_string()
1684 ]]
1685 )
1686 );
1687
1688 let e = Enforcer::new(
1689 "examples/rbac_model.conf",
1690 "examples/rbac_policy.csv",
1691 )
1692 .await
1693 .unwrap();
1694
1695 assert_eq!(
1696 e.enforce_ex(("alice", "data1", "read")).unwrap(),
1697 (
1698 true,
1699 vec![vec![
1700 "alice".to_string(),
1701 "data1".to_string(),
1702 "read".to_string()
1703 ]]
1704 )
1705 );
1706 assert_eq!(
1707 e.enforce_ex(("alice", "data1", "write")).unwrap(),
1708 (false, vec![])
1709 );
1710 assert_eq!(
1711 e.enforce_ex(("alice", "data2", "read")).unwrap(),
1712 (
1713 true,
1714 vec![vec![
1715 "data2_admin".to_string(),
1716 "data2".to_string(),
1717 "read".to_string()
1718 ]]
1719 )
1720 );
1721 assert_eq!(
1722 e.enforce_ex(("alice", "data2", "write")).unwrap(),
1723 (
1724 true,
1725 vec![vec![
1726 "data2_admin".to_string(),
1727 "data2".to_string(),
1728 "write".to_string()
1729 ]]
1730 )
1731 );
1732 assert_eq!(
1733 e.enforce_ex(("bob", "data1", "read")).unwrap(),
1734 (false, vec![])
1735 );
1736 assert_eq!(
1737 e.enforce_ex(("bob", "data1", "write")).unwrap(),
1738 (false, vec![])
1739 );
1740 assert_eq!(
1741 e.enforce_ex(("bob", "data2", "read")).unwrap(),
1742 (false, vec![])
1743 );
1744 assert_eq!(
1745 e.enforce_ex(("bob", "data2", "write")).unwrap(),
1746 (
1747 true,
1748 vec![vec![
1749 "bob".to_string(),
1750 "data2".to_string(),
1751 "write".to_string()
1752 ]]
1753 )
1754 );
1755
1756 let e = Enforcer::new(
1757 "examples/priority_model.conf",
1758 "examples/priority_policy.csv",
1759 )
1760 .await
1761 .unwrap();
1762
1763 assert_eq!(
1764 e.enforce_ex(("alice", "data1", "read")).unwrap(),
1765 (
1766 true,
1767 vec![vec![
1768 "alice".to_string(),
1769 "data1".to_string(),
1770 "read".to_string(),
1771 "allow".to_string()
1772 ]]
1773 )
1774 );
1775 assert_eq!(
1776 e.enforce_ex(("alice", "data1", "write")).unwrap(),
1777 (
1778 false,
1779 vec![vec![
1780 "data1_deny_group".to_string(),
1781 "data1".to_string(),
1782 "write".to_string(),
1783 "deny".to_string()
1784 ]]
1785 )
1786 );
1787 assert_eq!(
1788 e.enforce_ex(("alice", "data2", "read")).unwrap(),
1789 (false, vec![])
1790 );
1791 assert_eq!(
1792 e.enforce_ex(("alice", "data2", "write")).unwrap(),
1793 (false, vec![])
1794 );
1795 assert_eq!(
1796 e.enforce_ex(("bob", "data1", "write")).unwrap(),
1797 (false, vec![])
1798 );
1799 assert_eq!(
1800 e.enforce_ex(("bob", "data2", "read")).unwrap(),
1801 (
1802 true,
1803 vec![vec![
1804 "data2_allow_group".to_string(),
1805 "data2".to_string(),
1806 "read".to_string(),
1807 "allow".to_string()
1808 ]]
1809 )
1810 );
1811 assert_eq!(
1812 e.enforce_ex(("bob", "data2", "write")).unwrap(),
1813 (
1814 false,
1815 vec![vec![
1816 "bob".to_string(),
1817 "data2".to_string(),
1818 "write".to_string(),
1819 "deny".to_string()
1820 ]]
1821 )
1822 );
1823 }
1824}