@@ -165,9 +165,7 @@ impl Authorizer {
165
165
pset : & PolicySet ,
166
166
entities : & Entities ,
167
167
) -> ResponseKind {
168
- let eval = Evaluator :: new ( q, entities, & self . extensions ) ;
169
-
170
- let results = self . evaluate_policies ( pset, eval) ;
168
+ let results = self . evaluate_policies_core ( pset, q, entities) ;
171
169
172
170
let errors = results
173
171
. errors
@@ -273,11 +271,56 @@ impl Authorizer {
273
271
}
274
272
}
275
273
276
- fn evaluate_policies < ' a > (
274
+ /// Returns a policy evaluation response for `q`.
275
+ pub fn evaluate_policies (
276
+ & self ,
277
+ pset : & PolicySet ,
278
+ q : Request ,
279
+ entities : & Entities ,
280
+ ) -> EvaluationResponse {
281
+ let EvaluationResults {
282
+ satisfied_permits,
283
+ satisfied_forbids,
284
+ global_deny_policies : _,
285
+ errors,
286
+ permit_residuals,
287
+ forbid_residuals,
288
+ } = self . evaluate_policies_core ( pset, q, entities) ;
289
+
290
+ let errors = errors
291
+ . into_iter ( )
292
+ . map ( |( pid, err) | AuthorizationError :: PolicyEvaluationError {
293
+ id : pid,
294
+ error : err,
295
+ } )
296
+ . collect ( ) ;
297
+
298
+ let satisfied_permits = satisfied_permits. iter ( ) . map ( |p| p. id ( ) . clone ( ) ) . collect ( ) ;
299
+ let satisfied_forbids = satisfied_forbids. iter ( ) . map ( |p| p. id ( ) . clone ( ) ) . collect ( ) ;
300
+
301
+ // PANIC SAFETY all policy IDs in the original policy are unique by construction
302
+ #[ allow( clippy:: unwrap_used) ]
303
+ let permit_residuals = PolicySet :: try_from_iter ( permit_residuals) . unwrap ( ) ;
304
+ // PANIC SAFETY all policy IDs in the original policy are unique by construction
305
+ #[ allow( clippy:: unwrap_used) ]
306
+ let forbid_residuals = PolicySet :: try_from_iter ( forbid_residuals) . unwrap ( ) ;
307
+
308
+ EvaluationResponse {
309
+ satisfied_permits,
310
+ satisfied_forbids,
311
+ errors,
312
+ permit_residuals,
313
+ forbid_residuals,
314
+ }
315
+ }
316
+
317
+ fn evaluate_policies_core < ' a > (
277
318
& ' a self ,
278
319
pset : & ' a PolicySet ,
279
- eval : Evaluator < ' _ > ,
320
+ q : Request ,
321
+ entities : & Entities ,
280
322
) -> EvaluationResults < ' a > {
323
+ let eval = Evaluator :: new ( q, entities, & self . extensions ) ;
281
324
let mut results = EvaluationResults :: default ( ) ;
282
325
let mut satisfied_policies = vec ! [ ] ;
283
326
@@ -628,8 +671,18 @@ mod test {
628
671
pset. add_static ( parser:: parse_policy ( Some ( "3" . to_string ( ) ) , src3) . unwrap ( ) )
629
672
. unwrap ( ) ;
630
673
631
- let r = a. is_authorized_core ( q, & pset, & es) . decision ( ) ;
674
+ let r = a. is_authorized_core ( q. clone ( ) , & pset, & es) . decision ( ) ;
632
675
assert_eq ! ( r, Some ( Decision :: Allow ) ) ;
676
+
677
+ let r = a. evaluate_policies ( & pset, q, & es) ;
678
+ assert ! ( r. satisfied_permits. contains( & PolicyID :: from_string( "1" ) ) ) ;
679
+ assert ! ( r. satisfied_forbids. is_empty( ) ) ;
680
+ assert ! ( r
681
+ . permit_residuals
682
+ . get( & PolicyID :: from_string( "3" ) )
683
+ . is_some( ) ) ;
684
+ assert ! ( r. forbid_residuals. is_empty( ) ) ;
685
+ assert ! ( r. errors. is_empty( ) ) ;
633
686
}
634
687
635
688
#[ test]
@@ -687,10 +740,20 @@ mod test {
687
740
)
688
741
} ) ;
689
742
let pset = PolicySet :: try_from_iter ( new) . unwrap ( ) ;
690
- let r = a. is_authorized ( q, & pset, & es) ;
743
+ let r = a. is_authorized ( q. clone ( ) , & pset, & es) ;
691
744
assert_eq ! ( r. decision, Decision :: Deny ) ;
692
745
}
693
746
}
747
+
748
+ let r = a. evaluate_policies ( & pset, q, & es) ;
749
+ assert ! ( r. satisfied_permits. contains( & PolicyID :: from_string( "1" ) ) ) ;
750
+ assert ! ( r. satisfied_forbids. is_empty( ) ) ;
751
+ assert ! ( r. errors. is_empty( ) ) ;
752
+ assert ! ( r. permit_residuals. is_empty( ) ) ;
753
+ assert ! ( r
754
+ . forbid_residuals
755
+ . get( & PolicyID :: from_string( "2" ) )
756
+ . is_some( ) ) ;
694
757
}
695
758
696
759
#[ test]
@@ -740,8 +803,18 @@ mod test {
740
803
. unwrap ( ) ;
741
804
pset. add_static ( parser:: parse_policy ( Some ( "4" . into ( ) ) , src4) . unwrap ( ) )
742
805
. unwrap ( ) ;
743
- let r = a. is_authorized_core ( q, & pset, & es) ;
806
+ let r = a. is_authorized_core ( q. clone ( ) , & pset, & es) ;
744
807
assert_eq ! ( r. decision( ) , Some ( Decision :: Deny ) ) ;
808
+
809
+ let r = a. evaluate_policies ( & pset, q, & es) ;
810
+ assert ! ( r. satisfied_permits. contains( & PolicyID :: from_string( "4" ) ) ) ;
811
+ assert ! ( r. satisfied_forbids. contains( & PolicyID :: from_string( "3" ) ) ) ;
812
+ assert ! ( r. errors. is_empty( ) ) ;
813
+ assert ! ( r. permit_residuals. is_empty( ) ) ;
814
+ assert ! ( r
815
+ . forbid_residuals
816
+ . get( & PolicyID :: from_string( "2" ) )
817
+ . is_some( ) ) ;
745
818
}
746
819
747
820
#[ test]
@@ -808,8 +881,18 @@ mod test {
808
881
809
882
pset. add_static ( parser:: parse_policy ( Some ( "3" . into ( ) ) , src3) . unwrap ( ) )
810
883
. unwrap ( ) ;
811
- let r = a. is_authorized_core ( q, & pset, & es) ;
884
+ let r = a. is_authorized_core ( q. clone ( ) , & pset, & es) ;
812
885
assert_eq ! ( r. decision( ) , Some ( Decision :: Deny ) ) ;
886
+
887
+ let r = a. evaluate_policies ( & pset, q, & es) ;
888
+ assert ! ( r. satisfied_permits. is_empty( ) ) ;
889
+ assert ! ( r. satisfied_forbids. contains( & PolicyID :: from_string( "3" ) ) ) ;
890
+ assert ! ( r. errors. is_empty( ) ) ;
891
+ assert ! ( r
892
+ . permit_residuals
893
+ . get( & PolicyID :: from_string( "2" ) )
894
+ . is_some( ) ) ;
895
+ assert ! ( r. forbid_residuals. is_empty( ) ) ;
813
896
}
814
897
}
815
898
// by default, Coverlay does not track coverage for lines after a line
@@ -850,6 +933,21 @@ impl PartialResponse {
850
933
}
851
934
}
852
935
936
+ /// Policy evaluation response returned from the `Authorizer`.
937
+ #[ derive( Debug , PartialEq , Clone ) ]
938
+ pub struct EvaluationResponse {
939
+ /// `PolicyID`s of the fully evaluated policies with a permit [`Effect`].
940
+ pub satisfied_permits : HashSet < PolicyID > ,
941
+ /// `PolicyID`s of the fully evaluated policies with a forbid [`Effect`].
942
+ pub satisfied_forbids : HashSet < PolicyID > ,
943
+ /// List of errors that occurred
944
+ pub errors : Vec < AuthorizationError > ,
945
+ /// Residual policies with a permit [`Effect`].
946
+ pub permit_residuals : PolicySet ,
947
+ /// Residual policies with a forbid [`Effect`].
948
+ pub forbid_residuals : PolicySet ,
949
+ }
950
+
853
951
/// Diagnostics providing more information on how a `Decision` was reached
854
952
#[ derive( Debug , PartialEq , Clone ) ]
855
953
pub struct Diagnostics {
0 commit comments