diff options
| author | Jakob L. Kreuze | 2023-12-21 13:20:58 -0500 |
|---|---|---|
| committer | Jakob L. Kreuze | 2023-12-21 13:20:58 -0500 |
| commit | be7067d632aa665c20f96d3b344a84c95b0f8ff8 (patch) | |
| tree | fc5564a72cc42c8a21d3e943f645afcaae78f5a5 | |
| parent | 5918f84a1a05881d93d9fab83104feca9981bfaa (diff) | |
Check-in remaining files
43 files changed, 7171 insertions, 211 deletions
diff --git a/benchmarks/Xacml.lean b/benchmarks/Xacml.lean new file mode 100644 index 0000000..8211c74 --- /dev/null +++ b/benchmarks/Xacml.lean @@ -0,0 +1,1111 @@ +------------------------------------------------------------------------ +---- Atoms ------------------------------------------------------------- +------------------------------------------------------------------------ +-- +-- # References +-- +-- - 7.6 Match evaluation +-- +------------------------------------------------------------------------ + +inductive MatchResult where + | is_match : MatchResult + | no_match : MatchResult + | indeterminate : MatchResult +deriving DecidableEq, BEq, Repr + +inductive Decision where + | permit : Decision + | deny : Decision + | indeterminate : Decision + | not_applicable : Decision +deriving DecidableEq, BEq, Repr + +-- This type is used to implement the semantics described in § 7.10 (Extended +-- Indeterminate). It is only relevant to combining algorithms. +inductive Decision' where + | permit : Decision' + | deny : Decision' + | indeterminate : Decision' + | indeterminate_d : Decision' + | indeterminate_p : Decision' + | indeterminate_dp : Decision' + | not_applicable : Decision' +deriving DecidableEq, BEq, Repr + +def Decision'.downcast : Decision' → Decision + | Decision'.permit => Decision.permit + | Decision'.deny => Decision.deny + | Decision'.indeterminate => Decision.indeterminate + | Decision'.indeterminate_d => Decision.indeterminate + | Decision'.indeterminate_p => Decision.indeterminate + | Decision'.indeterminate_dp => Decision.indeterminate + | Decision'.not_applicable => Decision.not_applicable + +instance : Coe Decision' Decision where + coe := Decision'.downcast + +inductive EffectType where + | permit : EffectType + | deny : EffectType +deriving DecidableEq, BEq, Repr + +namespace EffectType + def to_decision (e : EffectType) : Decision := + match e with + | EffectType.permit => Decision.permit + | EffectType.deny => Decision.deny + + def to_decision' (e : EffectType) : Decision' := + match e with + | EffectType.permit => Decision'.permit + | EffectType.deny => Decision'.deny +end EffectType + +------------------------------------------------------------------------ +---- Values ------------------------------------------------------------ +------------------------------------------------------------------------ +-- +-- From A.2 Data-types: "Although XML instances represent all data-types +-- as strings, an XACML PDP must operate on types of data that, while +-- they have string representations, are not just strings. Types such as +-- Boolean, integer, and double MUST be converted from their XML string +-- representations to values that can be compared with values in their +-- domain of discourse, such as numbers." +-- +-- The standard enumerates the types that must be supported by any +-- conforming implementaiton. This is represented in `XmlType`, and +-- `Value` is the representation of a value payload with its associated +-- type. +-- +------------------------------------------------------------------------ + +inductive XmlType + | string : XmlType + | boolean : XmlType + | integer : XmlType + | double : XmlType + | time : XmlType + | date : XmlType + | dateTime : XmlType + | anyURI : XmlType + | hexBinary : XmlType + | base64Binary : XmlType + | dayTimeDuration : XmlType + | yearMonthDuration : XmlType + | x500Name : XmlType + | rfc822Name : XmlType + | ipAddress : XmlType + | dnsName : XmlType +deriving DecidableEq, BEq, Repr + +def Primitive : Type := XmlType × String +deriving DecidableEq, BEq, Repr + +def Primitive.mk (type : XmlType) (inner : String) : Primitive := (type, inner) + +notation:65 "#<" lhs:65 "," rhs:66 ">" => Primitive.mk lhs rhs + +instance : Coe Bool Primitive where + coe b := + match b with + | true => #<XmlType.boolean, "True"> + | false => #<XmlType.boolean, "False"> + +-- Per 7.4 Expression evaluation, +-- +-- "XACML defines an evaluation result of "Indeterminate", which is said +-- to be the result of an invalid expression, or an operational error +-- occurring during the evaluation of the expression." + +instance : Coe (Option Primitive) Primitive where + coe b := + match b with + | Option.none => #<XmlType.boolean, "Indeterminate"> + | Option.some a => a + +structure Bag where + contents: List Primitive +deriving BEq, DecidableEq, Repr + +-- def Bag.beq (b₁ b₂ : Bag) : Bool := +-- b₁.contents.all (fun x => b₂.contents.count x == b₁.contents.count x) + +-- instance : BEq Bag where +-- beq := Bag.beq + +inductive Value where + | primitive (p : Primitive) : Value + | bag (b : Bag) : Value +deriving DecidableEq, Repr + +def Value.beq (v₁ v₂ : Value) : Bool := + match v₁ with + | Value.primitive p₁ => + match v₂ with + | Value.primitive p₂ => p₁ == p₂ + | Value.bag _ => false + | Value.bag b₁ => + match v₂ with + | Value.primitive _ => false + | Value.bag b₂ => b₁ == b₂ + +instance : BEq Value where + beq := Value.beq + +instance : Coe (Option Value) Value where + coe b := + match b with + | Option.none => Value.primitive (#<XmlType.boolean, "Indeterminate">) + | Option.some a => a + +instance : Coe (Option Value) MatchResult where + coe b := + match b with + | Option.some (Value.primitive (XmlType.boolean, "True")) => MatchResult.is_match + | Option.some (Value.primitive (XmlType.boolean, "False")) => MatchResult.no_match + | _ => MatchResult.indeterminate + +------------------------------------------------------------------------ +---- Attributes--------------------------------------------------------- +------------------------------------------------------------------------ +-- +-- # References +-- +-- - 5.46 Element <Attribute> +-- - 5.42 Element <Request> +-- +-- Attributes are categories into <Attributes> elements. In this +-- implementation, categories are rolled up - every attribute carries +-- the category of its enclosing <Attributes> element. +-- +------------------------------------------------------------------------ + +structure Attribute where + category : String + identifier : String + issuer : Option String + value : Primitive +deriving DecidableEq, Repr + +def Attribute.beq (a₁ a₂ : Attribute) : Bool := + match a₁ with + | { category := category₁, + identifier := identifier₁, + issuer := issuer₁, + value := value₁ } => + match a₂ with + | { category := category₂, + identifier := identifier₂, + issuer := issuer₂, + value := value₂ } => + category₁ == category₂ + && identifier₁ == identifier₂ + && issuer₁ == issuer₂ + && value₁ == value₂ + +instance : BEq Attribute where + beq := Attribute.beq + +-- More than one attribute with a particular (category, identifier, issuer) can +-- exist in a `Request`. Indeed, this is how poly-valued attributes are +-- represented. + +def Request : Type := List Attribute +deriving Repr + +--- + +def Identifier : Type := String +deriving DecidableEq, BEq, Repr + +inductive RuleCombinatorAlgorithm where + | deny_overrides : RuleCombinatorAlgorithm + | ordered_deny_overrides : RuleCombinatorAlgorithm + | permit_overrides : RuleCombinatorAlgorithm + | ordered_permit_overrides : RuleCombinatorAlgorithm + | deny_unless_permit : RuleCombinatorAlgorithm + | permit_unless_deny : RuleCombinatorAlgorithm + | first_applicable : RuleCombinatorAlgorithm + | legacy_deny_overrides : RuleCombinatorAlgorithm + | legacy_ordered_deny_overrides : RuleCombinatorAlgorithm + | legacy_permit_overrides : RuleCombinatorAlgorithm + | legacy_ordered_permit_overrides : RuleCombinatorAlgorithm + +namespace RuleCombinatorAlgorithm + -- The output of a combining algorithm which does not track the extended set + -- of “Indeterminate” values MUST be treated as “Indeterminate{DP}” for the + -- value “Indeterminate” by a combining algorithm which tracks the extended + -- set of “Indeterminate” values. A combining algorithm which does not track + -- the extended set of “Indeterminate” values MUST treat the output of a + -- combining algorithm which tracks the extended set of “Indeterminate” values + -- as an “Indeterminate” for any of the possible values of the extended set of + -- “Indeterminate”. + + def eval_deny_overrides (results : List Decision') : Decision' := + if results.elem Decision'.deny then Decision'.deny else + if results.elem Decision'.indeterminate_dp then Decision'.indeterminate_dp else + if results.elem Decision'.indeterminate_d ∧ results.elem Decision'.indeterminate_p then Decision'.indeterminate_dp else + if results.elem Decision'.indeterminate_d then Decision'.indeterminate_d else + if results.elem Decision'.permit then Decision'.permit else + if results.elem Decision'.indeterminate_p then Decision'.indeterminate_p else + Decision'.not_applicable + def eval_ordered_deny_overrides : List Decision' -> Decision' := eval_deny_overrides + + def eval_permit_overrides (results : List Decision') : Decision' := + if results.elem Decision'.permit then Decision'.permit else + if results.elem Decision'.indeterminate_dp then Decision'.indeterminate_dp else + if results.elem Decision'.indeterminate_d ∧ results.elem Decision'.indeterminate_p then Decision'.indeterminate_dp else + if results.elem Decision'.indeterminate_p then Decision'.indeterminate_p else + if results.elem Decision'.deny then Decision'.deny else + if results.elem Decision'.indeterminate_d then Decision'.indeterminate_d else + Decision'.not_applicable + def eval_ordered_permit_overrides : List Decision' -> Decision' := eval_permit_overrides + + def eval_deny_unless_permit (results : List Decision') : Decision' := + if results.elem Decision'.permit then Decision'.permit else Decision'.deny + + def eval_permit_unless_deny (results : List Decision') : Decision' := + if results.elem Decision'.deny then Decision'.deny else Decision'.permit + + -- The non-normative part of the specification asserts that "If an error + -- occurs while evaluating the target or condition of a rule, then the + -- evaluation SHALL halt, and the policy shall evaluate to "Indeterminate", + -- with the appropriate error status." + -- + -- This behavior isn't spelled out in the normative part, because errors are + -- represented as an Indeterminate. + def eval_first_applicable (results : List Decision') : Decision' := + match (results.filter (fun d => d != Decision'.not_applicable)).get? 0 with + | some a => a + | none => Decision'.not_applicable + + def eval_legacy_deny_overrides (results : List Decision') : Decision' := + -- Note that "any rule having Effect=Deny evaluates to Indeterminate" + -- corresponds to indeterminate_d, and "any rule having Effect=Permit + -- evaluates to Indeterminate" corresponds to indeterminate_p. + if results.elem Decision'.deny then Decision'.deny else + if results.elem Decision'.indeterminate_d then Decision'.indeterminate else + if results.elem Decision'.permit then Decision'.permit else + if results.elem Decision'.indeterminate_p then Decision'.indeterminate else + Decision'.not_applicable + def eval_legacy_ordered_deny_overrides : List Decision' -> Decision' := eval_legacy_deny_overrides + + -- See the comment for `eval_legacy_deny_overrides_rule`. + def eval_legacy_permit_overrides (results : List Decision') : Decision' := + if results.elem Decision'.permit then Decision'.permit else + if results.elem Decision'.indeterminate_p then Decision'.indeterminate else + if results.elem Decision'.deny then Decision'.deny else + if results.elem Decision'.indeterminate_d then Decision'.indeterminate else + Decision'.not_applicable + def eval_legacy_ordered_permit_overrides : List Decision' -> Decision' := eval_legacy_permit_overrides +end RuleCombinatorAlgorithm + +inductive PolicyCombinatorAlgorithm where + | deny_overrides : PolicyCombinatorAlgorithm + | ordered_deny_overrides : PolicyCombinatorAlgorithm + | permit_overrides : PolicyCombinatorAlgorithm + | ordered_permit_overrides : PolicyCombinatorAlgorithm + | deny_unless_permit : PolicyCombinatorAlgorithm + | permit_unless_deny : PolicyCombinatorAlgorithm + | first_applicable : PolicyCombinatorAlgorithm + | only_one_applicable : PolicyCombinatorAlgorithm + | legacy_deny_overrides : PolicyCombinatorAlgorithm + | legacy_ordered_deny_overrides : PolicyCombinatorAlgorithm + | legacy_permit_overrides : PolicyCombinatorAlgorithm + | legacy_ordered_permit_overrides : PolicyCombinatorAlgorithm + +namespace PolicyCombinatorAlgorithm + def eval_deny_overrides := RuleCombinatorAlgorithm.eval_deny_overrides + def eval_ordered_deny_overrides := RuleCombinatorAlgorithm.eval_ordered_deny_overrides + def eval_permit_overrides := RuleCombinatorAlgorithm.eval_permit_overrides + def eval_ordered_permit_overrides := RuleCombinatorAlgorithm.eval_ordered_permit_overrides + def eval_deny_unless_permit := RuleCombinatorAlgorithm.eval_deny_unless_permit + def eval_permit_unless_deny := RuleCombinatorAlgorithm.eval_permit_unless_deny + def eval_first_applicable := RuleCombinatorAlgorithm.eval_first_applicable + + -- The non-normative part of the specification asserts that "If an error + -- occurs while evaluating the target or condition of a rule, then the + -- evaluation SHALL halt, and the policy shall evaluate to "Indeterminate", + -- with the appropriate error status." + -- + -- This behavior isn't spelled out in the normative part, because errors are + -- represented as an Indeterminate. + def eval_only_one_applicable (results : List Decision') : Decision' := + match results.filter (fun d => d != Decision'.not_applicable) with + | [] => Decision'.not_applicable + | [a] => a + | _ => Decision'.indeterminate + + def eval_legacy_deny_overrides (results : List Decision') : Decision' := + if results.elem Decision'.deny then Decision'.deny else + if results.elem Decision'.indeterminate then Decision'.deny else + if results.elem Decision'.permit then Decision'.permit else + Decision'.not_applicable + def eval_legacy_ordered_deny_overrides : List Decision' -> Decision' := eval_legacy_deny_overrides + + -- See the comment for `eval_legacy_deny_overrides`. + def eval_legacy_permit_overrides (results : List Decision') : Decision' := + if results.elem Decision'.permit then Decision'.permit else + if results.elem Decision'.deny then Decision'.deny else + if results.elem Decision'.indeterminate then Decision'.indeterminate else + Decision'.not_applicable + def eval_legacy_ordered_permit_overrides : List Decision' -> Decision' := eval_legacy_permit_overrides +end PolicyCombinatorAlgorithm + +inductive StatusCode + | ok : StatusCode + | missing_attribute : StatusCode + | syntax_error : StatusCode + | processing_error : StatusCode +deriving DecidableEq, BEq, Repr + +structure AttributeDesignator where + category : String + identifier : String + type : XmlType + issuer : Option String + must_be_present : Bool +deriving DecidableEq, BEq, Repr + +namespace AttributeDesignator + -- A named attribute SHALL match an attribute if the values of their + -- respective Category, AttributeId, DataType and Issuer attributes + -- match. The attribute designator’s Category MUST match, by + -- identifier equality, the Category of the <Attributes> element in + -- which the attribute is present. The attribute designator’s + -- AttributeId MUST match, by identifier equality, the AttributeId of + -- the attribute. The attribute designator’s DataType MUST match, by + -- identifier equality, the DataType of the same attribute. + -- + -- If the Issuer attribute is present in the attribute designator, + -- then it MUST match, using the + -- “urn:oasis:names:tc:xacml:1.0:function:string-equal” function, the + -- Issuer of the same attribute. If the Issuer is not present in the + -- attribute designator, then the matching of the attribute to the + -- named attribute SHALL be governed by AttributeId and DataType + -- attributes alone. + def matches? (designator : AttributeDesignator) (attr : Attribute) : Bool := + attr.category == designator.category + && attr.identifier == designator.identifier + && attr.value.fst == designator.type + && (attr.issuer == Option.none ∨ attr.issuer == designator.issuer) + + def eval (designator : AttributeDesignator) (context : List Attribute) : Sum Value (List StatusCode) := + let found := context.filter designator.matches? + let found := found.map (fun x => x.value) + if designator.must_be_present then + match found with + | [] => Sum.inr $ [StatusCode.missing_attribute] + | _ => Sum.inl $ Value.bag (Bag.mk found) + else Sum.inl $ Value.bag (Bag.mk found) +end AttributeDesignator + +def matches? (designator : AttributeDesignator) (attr : Attribute) : Prop := + designator.category == attr.category ∧ + designator.identifier == attr.identifier ∧ + designator.type == attr.value.fst ∧ + match (designator.issuer, attr.issuer) with + | (none, _) => True + | (some issuer₁, some issuer₂) => issuer₁ == issuer₂ + | _ => False + +def FunctionID : Type := String +deriving DecidableEq, BEq, Repr + +-- "The <Expression> element is not used directly in a policy. The <Expression> +-- element signifies that an element that extends the ExpressionType and is a +-- member of the <Expression> element substitution group SHALL appear in its +-- place." +-- +-- We omit the `<xacml:AttributeSelector>` case because this model of XACML does +-- not include it, and we exclude the `<xacml:VariableReference>` case because +-- we erase variable references in the compiler. + +inductive Expression where + -- Note well that `apply` accepts a list of Values, not a list of Expressions, + -- as its arguments. The compiler is responsible for ensuring that the + -- arguments in a function call are fully evaluated. + -- + -- Lean is quite strict about recursion being bounded, which is a little hard + -- to prove in our case! Fortunately, we can punt the job of proving that to + -- the compiler. + | apply (function : FunctionID) (args: List Value) : Expression + | attribute_designator (inner : AttributeDesignator) : Expression + | attribute_value (inner : Value) : Expression + | function (function : FunctionID) : Expression +deriving DecidableEq, BEq, Repr + +namespace Expression + def apply_eval (name : FunctionID) (args : List Value) : Option Value := + if name == "urn:oasis:names:tc:xacml:1.0:function:string-equal" then + match args with + | [Value.primitive (XmlType.string, lhs), + Value.primitive (XmlType.string, rhs)] => + Value.primitive (lhs == rhs) + | _ => Value.primitive (#<XmlType.boolean, "Indeterminate">) + else if name == "urn:oasis:names:tc:xacml:1.0:function:anyURI-equal" then + match args with + | [Value.primitive (XmlType.anyURI, lhs), + Value.primitive (XmlType.anyURI, rhs)] => + Value.primitive (lhs == rhs) + | _ => Value.primitive (#<XmlType.boolean, "Indeterminate">) + else if name == "urn:oasis:names:tc:xacml:1.0:function:integer-equal" then + match args with + | [Value.primitive (XmlType.integer, lhs), + Value.primitive (XmlType.integer, rhs)] => + Value.primitive (lhs == rhs) + | _ => Value.primitive (#<XmlType.boolean, "Indeterminate">) + else Option.none + + def eval (expression : Expression) (context : Request) : Option Value := + -- The return type of `<Apply>` may be made more specific by type unification. + -- + -- The evaluation result can be specified to be "Indeterminate"; we encode + -- this as `Option.none` here for ergonomics, but we do give an instance for + -- `Coe (Option Value) Value`. + -- + -- § 7.6 enumerates but does not describe the semantics for: + -- + -- - <xacml:AttributeValue> + -- - <xacml:AttributeDesignator> + -- - <xacml:AttributeSelector> + -- - <xacml:Apply> + -- - <xacml:Function> + -- - <xacml:VariableReference> + match expression with + | Expression.apply name args => apply_eval name args + | Expression.attribute_designator inner => + match inner.eval context with + | Sum.inl res => res + | Sum.inr _ => Option.none + | Expression.attribute_value inner => some inner + | _ => Option.none +end Expression + +structure Match where + function : Identifier + designator : AttributeDesignator + value : Value +deriving DecidableEq, BEq, Repr +def AllOf : Type := List Match +deriving DecidableEq, BEq, Repr +def AnyOf : Type := List AllOf +deriving DecidableEq, BEq, Repr +def Target : Type := List AnyOf +deriving DecidableEq, BEq, Repr + +instance : Membership AllOf AnyOf where + mem := fun x y => y.contains x + +namespace Match + -- The evaluation semantics for a matching element is as follows. + -- + -- 1. If an operational error were to occur while evaluating the + -- <AttributeDesignator> or <AttributeSelector> element, then the + -- result of the entire expression SHALL be "Indeterminate". + -- + -- 2. If the <AttributeDesignator> or <AttributeSelector> element were + -- to evaluate to an empty bag, then the result of the expression + -- SHALL be "False". + -- + -- 3. Otherwise, the MatchId function SHALL be applied between the + -- <AttributeValue> and each element of the bag returned from the + -- <AttributeDesignator> or <AttributeSelector> element. + -- a. If at least one of those function applications were to evaluate + -- to "True", then the result of the entire expression SHALL be + -- "True". + -- b. Otherwise, if at least one of the function applications results + -- in "Indeterminate", then the result SHALL be "Indeterminate". + -- c. Finally, if all function applications evaluate to "False", then + -- the result of the entire expression SHALL be "False". + def eval (m : Match) (context : Request) : Option Value := + match m with + | Match.mk fn designator value => + match designator.eval context with + | Sum.inl result => + let results := match result with + -- Otherwise, the MatchId function SHALL be applied between the + -- <AttributeValue> and each element of the bag returned from the + -- <AttributeDesignator> or <AttributeSelector> element. + | (Value.bag (Bag.mk attrs)) => + attrs.map fun attr => + let args := [value, Value.primitive attr] + (Expression.apply fn args).eval context + | (Value.primitive attr) => + -- TODO: Prove that this case is impossible. + let args := [value, Value.primitive attr] + [(Expression.apply fn args).eval context] + + let results := results.map (fun (x : Option Value) => (x : Value)) + -- If at least one of those function applications were to evaluate to + -- "True", then the result of the entire expression SHALL be "True". + if results.elem (Value.primitive (#<XmlType.boolean, "True">)) then + (Value.primitive (#<XmlType.boolean, "True">)) + -- Otherwise, if at least one of the function applications results in + -- "Indeterminate", then the result SHALL be "Indeterminate". + else if results.elem (Value.primitive (#<XmlType.boolean, "Indeterminate">)) then + (Value.primitive (#<XmlType.boolean, "Indeterminate">)) + -- The `else` arm handles the following cases: + -- + -- If the <AttributeDesignator> or <AttributeSelector> element were to + -- evaluate to an empty bag, then the result of the expression SHALL + -- be "False". + -- + -- Finally, if all function applications evaluate to "False", then the + -- result of the entire expression SHALL be "False". + else + Value.primitive (#<XmlType.boolean, "False">) + -- If an operational error were to occur while evaluating the + -- <AttributeDesignator> or <AttributeSelector> element, then the result + -- of the entire expression SHALL be "Indeterminate". + | Sum.inr _ => Option.none +end Match + +namespace AllOf + def eval (conj : AllOf) (context : Request) : MatchResult := + let result := conj.map (fun x => x.eval context) + let result := result.map (fun (x : Option Value) => (x : Value)) + if result.all (fun x => x == Value.primitive (XmlType.boolean, "True")) then MatchResult.is_match + else if result.all (fun x => x != Value.primitive (XmlType.boolean, "False")) ∧ + result.elem (Value.primitive (XmlType.boolean, "Indeterminate")) + then MatchResult.indeterminate + else MatchResult.no_match +end AllOf + +namespace AnyOf + def eval (disj : AnyOf) (context : Request) : MatchResult := + -- match disj with + -- | [] => MatchResult.is_match + -- | List.cons x xs => match x.eval context with + -- | MatchResult.is_match => MatchResult.is_match + -- | MatchResult.no_match => + -- let rest := AnyOf.eval xs context + -- if rest == MatchResult.no_match then MatchResult.no_match else rest + -- | MatchResult.indeterminate => + -- let rest := AnyOf.eval xs context + -- if rest == MatchResult.no_match then MatchResult.indeterminate else rest + if disj.isEmpty then MatchResult.is_match else + let result := disj.map (fun x => x.eval context) + if result.any (fun x => x == MatchResult.is_match) then MatchResult.is_match + else if result.elem MatchResult.indeterminate then MatchResult.indeterminate + else MatchResult.no_match +end AnyOf + +namespace Target + def eval (target : Target) (context : Request) : MatchResult := + match target with + -- An empty target matches any request. + | [] => MatchResult.is_match + | xs => + let results := xs.map (fun disj => disj.eval context) + -- Otherwise the target value SHALL be "Match" if all the AnyOf + -- specified in the target match values in the request context. + if results.all (fun result => result == MatchResult.is_match) then + MatchResult.is_match + -- Otherwise, if any one of the AnyOf specified in the target is “No + -- Match”, then the target SHALL be “No Match”. + else if results.any (fun result => result == MatchResult.no_match) then + MatchResult.no_match + -- Otherwise, the target SHALL be “Indeterminate”. + else MatchResult.indeterminate +end Target + +structure Obligation where + assignments : List Attribute + identifier : String +deriving DecidableEq, BEq, Repr + +structure Advice where + assignments : List Attribute + identifier : String +deriving DecidableEq, BEq, Repr + +structure AttributeAssignmentExpression where + category : String + identifier : String + issuer : Option String + expression : Expression +deriving DecidableEq, BEq, Repr + +namespace AttributeAssignmentExpression + def eval (assignment : AttributeAssignmentExpression) (context : Request) : Option Attribute := + match assignment.expression.eval context with + | some (Value.primitive inner) => + Attribute.mk + assignment.category + assignment.identifier + assignment.issuer + inner + | _ => none +end AttributeAssignmentExpression + +structure ObligationExpression where + assignments : List AttributeAssignmentExpression + identifier : String + fulfill_on : Decision +deriving DecidableEq, BEq, Repr + +namespace ObligationExpression + def eval (obligation : ObligationExpression) (context : Request) : Option Obligation := + let assignments := obligation.assignments.map (fun x => AttributeAssignmentExpression.eval x context) + if assignments.all Option.isSome then + Obligation.mk + (List.filterMap id assignments) + obligation.identifier + else none +end ObligationExpression + +structure AdviceExpression where + assignments : List AttributeAssignmentExpression + identifier : String + applies_to : Decision +deriving DecidableEq, BEq, Repr + +namespace AdviceExpression + def eval (advice : AdviceExpression) (context : Request) : Option Advice := + let assignments := advice.assignments.map (fun x => AttributeAssignmentExpression.eval x context) + if assignments.all Option.isSome then + Advice.mk + (List.filterMap id assignments) + advice.identifier + else none +end AdviceExpression + +structure ResultAuxiliary where + status : Option (List StatusCode) + obligations : List Obligation + advice : List Advice +deriving DecidableEq, BEq, Repr + +structure ResultAuxiliary' where + status : Option (List StatusCode) + obligations : List ObligationExpression + advice : List AdviceExpression +deriving DecidableEq, BEq, Repr + +def collect_option {α : Type} (xs : List (Option α)) : Option (List α) := + match xs with + | [] => some [] + | some x :: xs' => + match collect_option xs' with + | some xs' => some (x :: xs') + | none => none + | none :: _ => none + +namespace ResultAuxiliary' + def eval (result : ResultAuxiliary') (context : Request) : Option ResultAuxiliary := + let advice := + collect_option (List.map (fun x => AdviceExpression.eval x context) result.advice) + let obligations := + collect_option (List.map (fun x => ObligationExpression.eval x context) result.obligations) + match (obligations, advice) with + | (some obligations, some advice) => + some { status := result.status, obligations, advice } + | _ => none +end ResultAuxiliary' + +structure MissingAttributeDetail where + category : String + identifier : String + issuer : Option String + value : Option Value + type : XmlType +deriving DecidableEq, BEq, Repr + +def Result : Type := Decision' × (Option ResultAuxiliary) +def Result' : Type := Decision' × (Option ResultAuxiliary') + +namespace Result' + def eval (result : Result') (context : Request) : Result := + match result.snd with + | some aux => + let advices := aux.advice.map (fun advice => AdviceExpression.eval advice context) + let obligations := aux.obligations.map (fun x => ObligationExpression.eval x context) + if advices.any Option.isNone || obligations.any Option.isNone then + (Decision'.indeterminate, none) + else + ( + result.fst, + ResultAuxiliary.mk + aux.status + (List.filterMap id obligations) + (List.filterMap id advices) + ) + | none => (result.fst, none) +end Result' + +structure Rule where + target : Target + condition : Option Expression + effect : EffectType + obligations : List ObligationExpression + advice : List AdviceExpression + +namespace Rule + def eval (rule : Rule) (context : Request) : Result' := + let (decision : Decision') := + -- The "no target" case is handled within `Target.eval`, returning + -- `MatchResult.is_match` when the target is empty. + match rule.target.eval context with + | MatchResult.is_match => + let condition := + match rule.condition with + | some condition => + -- The condition value SHALL be "True" if the <Condition> element + -- evaluates to "True". + let result := condition.eval context + if result == some (Value.primitive (#<XmlType.boolean, "True">)) then result + -- Its value SHALL be "False" if the <Condition> element evaluates to + -- "False". + else if result == some (Value.primitive (#<XmlType.boolean, "False">)) then result + -- The condition value SHALL be "Indeterminate", if the expression + -- contained in the <Condition> element evaluates to "Indeterminate." + else Value.primitive (#<XmlType.boolean, "Indeterminate">) + -- The condition value SHALL be "True" if the <Condition> element is absent. + | none => Value.primitive (#<XmlType.boolean, "True">) + match condition with + | some (Value.primitive (XmlType.boolean, "False")) => Decision'.not_applicable + | some (Value.primitive (XmlType.boolean, "True")) => + match rule.effect with + | EffectType.permit => Decision'.permit + | EffectType.deny => Decision'.deny + -- | (#<XmlType.boolean, "Indeterminate">) => + | _ => + if rule.effect == EffectType.permit then + Decision'.indeterminate_p else + Decision'.indeterminate_d + | MatchResult.no_match => Decision'.not_applicable + | MatchResult.indeterminate => + if rule.effect == EffectType.permit then + Decision'.indeterminate_p else + Decision'.indeterminate_d + let advices := + rule.advice.filter + (fun advice => advice.applies_to == (decision : Decision)) + let obligations := + rule.obligations.filter + (fun obligation => obligation.fulfill_on == (decision : Decision)) + ( + decision, + ResultAuxiliary'.mk + none + obligations + advices + ) +end Rule + +structure Policy where + combinator : RuleCombinatorAlgorithm + target : Target + obligations : List ObligationExpression + advice : List AdviceExpression + +namespace Policy + def eval (policy : Policy) (child_results : List Result') (context : Request) : Result' := + let combinator := + match policy.combinator with + | RuleCombinatorAlgorithm.deny_overrides => RuleCombinatorAlgorithm.eval_deny_overrides + | RuleCombinatorAlgorithm.ordered_deny_overrides => RuleCombinatorAlgorithm.eval_ordered_deny_overrides + | RuleCombinatorAlgorithm.permit_overrides => RuleCombinatorAlgorithm.eval_permit_overrides + | RuleCombinatorAlgorithm.ordered_permit_overrides => RuleCombinatorAlgorithm.eval_ordered_permit_overrides + | RuleCombinatorAlgorithm.deny_unless_permit => RuleCombinatorAlgorithm.eval_deny_unless_permit + | RuleCombinatorAlgorithm.permit_unless_deny => RuleCombinatorAlgorithm.eval_permit_unless_deny + | RuleCombinatorAlgorithm.first_applicable => RuleCombinatorAlgorithm.eval_first_applicable + | RuleCombinatorAlgorithm.legacy_deny_overrides => RuleCombinatorAlgorithm.eval_legacy_deny_overrides + | RuleCombinatorAlgorithm.legacy_ordered_deny_overrides => RuleCombinatorAlgorithm.eval_legacy_ordered_deny_overrides + | RuleCombinatorAlgorithm.legacy_permit_overrides => RuleCombinatorAlgorithm.eval_legacy_permit_overrides + | RuleCombinatorAlgorithm.legacy_ordered_permit_overrides => RuleCombinatorAlgorithm.eval_legacy_ordered_permit_overrides + let (decision : Decision') := combinator (List.map Prod.fst child_results) + let (decision : Decision') := + match policy.target.eval context with + | MatchResult.is_match => decision + | MatchResult.no_match => Decision'.not_applicable + | MatchResult.indeterminate => + match decision with + | Decision'.not_applicable => Decision'.not_applicable + | Decision'.permit => Decision'.indeterminate_p + | Decision'.deny => Decision'.indeterminate_d + | Decision'.indeterminate => Decision'.indeterminate_dp + | Decision'.indeterminate_dp => Decision'.indeterminate_dp + | Decision'.indeterminate_p => Decision'.indeterminate_p + | Decision'.indeterminate_d => Decision'.indeterminate_d + let advices := + policy.advice.filter + (fun advice => advice.applies_to == (decision : Decision)) + ++ + List.join + (child_results.filterMap + (fun x => match x.snd with + | some y => y.advice + | none => none)) + let obligations := + policy.obligations.filter + (fun obligation => obligation.fulfill_on == (decision : Decision)) + ++ + List.join + (child_results.filterMap + (fun x => match x.snd with + | some y => y.obligations + | none => none)) + ( + decision, + ResultAuxiliary'.mk + none + obligations + advices + ) +end Policy + +structure PolicySet where + combinator : PolicyCombinatorAlgorithm + target : Target + obligations : List ObligationExpression + advice : List AdviceExpression + +namespace PolicySet + def eval (policyset : PolicySet) (child_results : List Result') (context : Request) : Result' := + let combinator := + match policyset.combinator with + | PolicyCombinatorAlgorithm.deny_overrides => PolicyCombinatorAlgorithm.eval_deny_overrides + | PolicyCombinatorAlgorithm.ordered_deny_overrides => PolicyCombinatorAlgorithm.eval_ordered_deny_overrides + | PolicyCombinatorAlgorithm.permit_overrides => PolicyCombinatorAlgorithm.eval_permit_overrides + | PolicyCombinatorAlgorithm.ordered_permit_overrides => PolicyCombinatorAlgorithm.eval_ordered_permit_overrides + | PolicyCombinatorAlgorithm.deny_unless_permit => PolicyCombinatorAlgorithm.eval_deny_unless_permit + | PolicyCombinatorAlgorithm.permit_unless_deny => PolicyCombinatorAlgorithm.eval_permit_unless_deny + | PolicyCombinatorAlgorithm.first_applicable => PolicyCombinatorAlgorithm.eval_first_applicable + | PolicyCombinatorAlgorithm.only_one_applicable => PolicyCombinatorAlgorithm.eval_only_one_applicable + | PolicyCombinatorAlgorithm.legacy_deny_overrides => PolicyCombinatorAlgorithm.eval_legacy_deny_overrides + | PolicyCombinatorAlgorithm.legacy_ordered_deny_overrides => PolicyCombinatorAlgorithm.eval_legacy_ordered_deny_overrides + | PolicyCombinatorAlgorithm.legacy_permit_overrides => PolicyCombinatorAlgorithm.eval_legacy_permit_overrides + | PolicyCombinatorAlgorithm.legacy_ordered_permit_overrides => PolicyCombinatorAlgorithm.eval_legacy_ordered_permit_overrides + let (decision : Decision') := combinator (List.map Prod.fst child_results) + let (decision : Decision') := + match policyset.target.eval context with + | MatchResult.is_match => decision + | MatchResult.no_match => Decision'.not_applicable + | MatchResult.indeterminate => + match decision with + | Decision'.not_applicable => Decision'.not_applicable + | Decision'.permit => Decision'.indeterminate_p + | Decision'.deny => Decision'.indeterminate_d + | Decision'.indeterminate => Decision'.indeterminate_dp + | Decision'.indeterminate_dp => Decision'.indeterminate_dp + | Decision'.indeterminate_p => Decision'.indeterminate_p + | Decision'.indeterminate_d => Decision'.indeterminate_d + let advices := + policyset.advice.filter + (fun advice => advice.applies_to == (decision : Decision)) + ++ + List.join + (child_results.filterMap + (fun x => match x.snd with + | some y => y.advice + | none => none)) + let obligations := + policyset.obligations.filter + (fun obligation => obligation.fulfill_on == (decision : Decision)) + ++ + List.join + (child_results.filterMap + (fun x => match x.snd with + | some y => y.obligations + | none => none)) + ( + decision, + ResultAuxiliary'.mk + none + obligations + advices + ) +end PolicySet + +inductive PolicyElement where + | PolicySet (ps : PolicySet) + | Policy (p : Policy) + | Rule (r : Rule) + +def PolicyElement.eval (context : Request) : PolicyElement -> List Result' -> Result' + | PolicySet ps, results => ps.eval results context + | Policy p, results => p.eval results context + | Rule r, _ => r.eval context + +inductive ElementTree where + | Node (e : PolicyElement) (xs : List ElementTree) + +def ElementTree.eval' (context : Request) : ElementTree -> List Result' -> Result' + | ElementTree.Node e [], results => PolicyElement.eval context e results + | ElementTree.Node e (x :: xs), results => + ElementTree.eval' + context + (ElementTree.Node e xs) + ((ElementTree.eval' context x []) :: results) + +def ElementTree.eval (context : Request) (et : ElementTree) : Result' := + ElementTree.eval' context et [] + +-- let results := policy.rules.map (fun rule => rule.eval context) + +def is_indeterminate (x : Expression) : Bool := + match x with + | Expression.attribute_value (Value.primitive (XmlType.boolean, "Indeterminate")) => true + | _ => false + +def make_response + (decision : Decision) + (status : Option (List StatusCode)) + (obligations : List Obligation) + (advice : List Advice) +: Decision × ResultAuxiliary := + let obligations := obligations.map (fun expr => Obligation.mk expr.assignments expr.identifier) + let advice := advice.map (fun expr => Advice.mk expr.assignments expr.identifier) + -- If any of the attribute assignment expressions in an obligation or + -- advice expression with a matching FulfillOn or AppliesTo attribute + -- evaluates to “Indeterminate”, then the whole rule, policy, or + -- policy set SHALL be “Indeterminate”. If the FulfillOn or AppliesTo + -- attribute does not match the result of the combining algorithm or + -- the rule evaluation, then any indeterminate in an obligation or + -- advice expression has no effect. + -- if obligations. + let decision := + -- if obligations.any + -- (fun obligation => obligation.assignments.any + -- (fun assignment => is_indeterminate assignment.expression)) ∨ + -- advice.any + -- (fun advice => advice.assignments.any + -- (fun assignment => is_indeterminate assignment.expression)) + -- then + -- Decision.indeterminate + -- else + decision + ( + decision, + ResultAuxiliary.mk + status + (obligations.map (fun expr => Obligation.mk expr.assignments expr.identifier)) + (advice.map (fun expr => Advice.mk expr.assignments expr.identifier)) + ) + +def combine_response_aux (x y : ResultAuxiliary) : ResultAuxiliary := + match (x, y) with + | (ResultAuxiliary.mk status₁ obligations₁ advice₁, + ResultAuxiliary.mk _ obligations₂ advice₂) => + ResultAuxiliary.mk + status₁ + (obligations₁ ++ obligations₂) + (advice₁ ++ advice₂) + +def Choice : Type := List (Decision × ResultAuxiliary) +deriving DecidableEq, BEq, Repr + +def xml_of_decision (decision : Decision) := + match decision with + | Decision.permit => "<Decision>Permit</Decision>" + | Decision.deny => "<Decision>Deny</Decision>" + | Decision.indeterminate => "<Decision>Indeterminate</Decision>" + | Decision.not_applicable => "<Decision>NotApplicable</Decision>" + +def string_of_status_code (code : StatusCode) := + match code with + | StatusCode.ok => "urn:oasis:names:tc:xacml:1.0:status:ok" + | StatusCode.missing_attribute => "urn:oasis:names:tc:xacml:1.0:status:missing-attribute" + | StatusCode.syntax_error => "urn:oasis:names:tc:xacml:1.0:status:syntax-error" + | StatusCode.processing_error => "urn:oasis:names:tc:xacml:1.0:status:processing-error" + +def xml_of_status_code (status : List StatusCode) := + match status with + | primary :: [] => String.join [ + "<StatusCode Value=\"", + string_of_status_code primary, + "\"/>"] + | primary :: rest => String.join [ + "<StatusCode Value=\"", + string_of_status_code primary, + "\">", + xml_of_status_code rest, "</StatusCode>"] + | _ => "" + +def xml_of_status (status : List StatusCode) := + match status with + | [] => "" + | codes => String.join ["<Status>", xml_of_status_code codes, "</Status>"] + +def xml_of_xmltype : XmlType -> String + | XmlType.string => "http://www.w3.org/2001/XMLSchema#string" + | XmlType.boolean => "http://www.w3.org/2001/XMLSchema#boolean" + | XmlType.integer => "http://www.w3.org/2001/XMLSchema#integer" + | XmlType.double => "http://www.w3.org/2001/XMLSchema#double" + | XmlType.time => "http://www.w3.org/2001/XMLSchema#time" + | XmlType.date => "http://www.w3.org/2001/XMLSchema#date" + | XmlType.dateTime => "http://www.w3.org/2001/XMLSchema#dateTime" + | XmlType.dayTimeDuration => "http://www.w3.org/2001/XMLSchema#dayTimeDuration" + | XmlType.yearMonthDuration => "http://www.w3.org/2001/XMLSchema#yearMonthDuration" + | XmlType.anyURI => "http://www.w3.org/2001/XMLSchema#anyURI" + | XmlType.hexBinary => "http://www.w3.org/2001/XMLSchema#hexBinary" + | XmlType.base64Binary => "http://www.w3.org/2001/XMLSchema#base64Binary" + | XmlType.rfc822Name => "urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name" + | XmlType.x500Name => "urn:oasis:names:tc:xacml:1.0:data-type:x500Name" + | XmlType.ipAddress => "urn:oasis:names:tc:xacml:2.0:data-type:ipAddress" + | XmlType.dnsName => "urn:oasis:names:tc:xacml:2.0:data-type:dnsName" + +def xml_of_attribute_assignment (assignment : Attribute) := + String.join [ + "<AttributeAssignment AttributeId=\"", + assignment.identifier, + "\" DataType=\"", + xml_of_xmltype assignment.value.fst, + "\" Category=\"", + assignment.category, + (match assignment.issuer with + | some issuer => String.join ["\" Issuer=\"", issuer] + | none => ""), + "\"/>" + ] + +def xml_of_obligation (obligation : Obligation) := + String.join [ + "<Obligation ObligationId=\"", + obligation.identifier, + "\">", + String.join (List.map xml_of_attribute_assignment obligation.assignments), + "</Obligation>" + ] + +def xml_of_obligations (obligations : List Obligation) := + String.join ["<Obligations>", String.join (List.map xml_of_obligation obligations), "</Obligations>"] + +def xml_of_advice (advice : Advice) := + String.join [ + "<Advice AdviceId=\"", + advice.identifier, + "\">", + String.join (List.map xml_of_attribute_assignment advice.assignments), + "</Advice>" + ] + +def xml_of_advices (advices : List Advice) := + String.join ["<AssociatedAdvice>", String.join (List.map xml_of_advice advices), "</AssociatedAdvice>"] + +def xml_of_response (response : Result) := + String.join [ + "<?xml version=\"1.0\" encoding=\"UTF-8\"?>", + "<Response xmlns=\"urn:oasis:names:tc:xacml:3.0:core:schema:wd-17\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">", + "<Result>", + xml_of_decision response.fst, + (match response.snd with + | some {status, obligations, advice} => + String.join [ + (match status with + | some status => xml_of_status status + | none => "<Status><StatusCode Value=\"urn:oasis:names:tc:xacml:1.0:status:ok\"/></Status>"), + (match obligations with + | [] => "" + | _ => xml_of_obligations obligations), + (match advice with + | [] => "" + | _ => xml_of_advices advice) + ] + | none => ""), + "</Result>", + "</Response>" + ] diff --git a/benchmarks/authzforce-harness.bash b/benchmarks/authzforce-harness.bash new file mode 100644 index 0000000..f339446 --- /dev/null +++ b/benchmarks/authzforce-harness.bash @@ -0,0 +1,23 @@ +#!/usr/bin/env bash + +NAME="$(basename $1)" +if [ $NAME = "IIA001" ]; then + NAME="IIA1" +fi + +cat > /tmp/pdp.xml <<EOF +<?xml version="1.0" encoding="UTF-8"?> +<pdp xmlns="http://authzforce.github.io/core/xmlns/pdp/8" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + version="8.0"> + <policyProvider id="rootPolicyProvider" xsi:type="StaticPolicyProvider"> + <policyLocation>$1/Policy.xml</policyLocation> + </policyProvider> + <rootPolicyRef>urn:oasis:names:tc:xacml:2.0:conformance-test:$NAME:policy</rootPolicyRef> + <ioProcChain> + <requestPreproc>urn:ow2:authzforce:feature:pdp:request-preproc:xacml-json:default-lax</requestPreproc> + <resultPostproc>urn:ow2:authzforce:feature:pdp:result-postproc:xacml-json:default</resultPostproc> + </ioProcChain> +</pdp> +EOF +java -jar /tmp/authzforce-ce-core-pdp-cli-21.0.1.jar /tmp/pdp.xml $1/Request.xml diff --git a/benchmarks/collection.sh b/benchmarks/collection.sh new file mode 100644 index 0000000..e502788 --- /dev/null +++ b/benchmarks/collection.sh @@ -0,0 +1,2 @@ +export BENCHMARK=/tmp/core/pdp-testutils/src/test/resources/conformance/xacml-3.0-from-2.0-ct/mandatory/IIA001 +/tmp/hyperfine/target/release/hyperfine --export-json=hyperfine-iia001.json "bash authzforce-harness.bash $BENCHMARK" "bash lean-harness.bash $BENCHMARK" "bash rego-harness.bash $BENCHMARK" diff --git a/benchmarks/excluded.txt b/benchmarks/excluded.txt new file mode 100644 index 0000000..2bfb31b --- /dev/null +++ b/benchmarks/excluded.txt @@ -0,0 +1,1822 @@ +mandatory/IIA008/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:anyURI-equal +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-is-in + +mandatory/IIA009/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:anyURI-equal +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-is-in + +mandatory/IIA016_FIXED/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:time-equal +urn:oasis:names:tc:xacml:1.0:function:time-one-and-only + +mandatory/IIA017/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:time-bag-size + +mandatory/IIA018_FIXED/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:date-equal +urn:oasis:names:tc:xacml:1.0:function:date-one-and-only + +mandatory/IIA019/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:date-bag-size +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIA020_FIXED/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-equal +urn:oasis:names:tc:xacml:1.0:function:dateTime-one-and-only + +mandatory/IIA021/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-bag-size +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIB008/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:anyURI-equal +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-regexp-match + +mandatory/IIB009/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:anyURI-equal +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-regexp-match + +mandatory/IIB014/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:anyURI-equal +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:x500Name-equal + +mandatory/IIB015/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:anyURI-equal +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:x500Name-equal + +mandatory/IIB026/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:anyURI-equal +urn:oasis:names:tc:xacml:1.0:function:dateTime-equal +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIB027/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:anyURI-equal +urn:oasis:names:tc:xacml:1.0:function:dateTime-equal +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIC001/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract + +mandatory/IIC002/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-subtract + +mandatory/IIC004/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract + +mandatory/IIC007/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract + +mandatory/IIC008/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:string-is-in + +mandatory/IIC009/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:string-is-in + +mandatory/IIC010/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract + +mandatory/IIC011/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract + +mandatory/IIC012/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract + +mandatory/IIC013/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-add +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only + +mandatory/IIC014/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-add +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only + +mandatory/IIC015/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-add +urn:oasis:names:tc:xacml:1.0:function:double-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only + +mandatory/IIC016/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract + +mandatory/IIC017/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only +urn:oasis:names:tc:xacml:1.0:function:double-subtract + +mandatory/IIC018/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-multiply +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only + +mandatory/IIC019/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:double-multiply +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only + +mandatory/IIC020/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-divide +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only + +mandatory/IIC021/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-divide +urn:oasis:names:tc:xacml:1.0:function:double-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only + +mandatory/IIC022/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:integer-mod +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only + +mandatory/IIC024/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only +urn:oasis:names:tc:xacml:1.0:function:round + +mandatory/IIC025/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only +urn:oasis:names:tc:xacml:1.0:function:floor + +mandatory/IIC026/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-abs +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract + +mandatory/IIC027/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-abs +urn:oasis:names:tc:xacml:1.0:function:double-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only +urn:oasis:names:tc:xacml:1.0:function:double-subtract + +mandatory/IIC028/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only +urn:oasis:names:tc:xacml:1.0:function:double-to-integer +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract + +mandatory/IIC029/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:integer-to-double + +mandatory/IIC030/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract + +mandatory/IIC031/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract + +mandatory/IIC032/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:integer-to-double + +mandatory/IIC033/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:integer-to-double + +mandatory/IIC034/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:boolean-equal +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract + +mandatory/IIC035/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:boolean-equal +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract + +mandatory/IIC038/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-equal +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-one-and-only + + +mandatory/IIC039/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-equal +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-one-and-only + + +mandatory/IIC040/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:x500Name-equal +urn:oasis:names:tc:xacml:1.0:function:x500Name-one-and-only + + +mandatory/IIC041/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:x500Name-equal +urn:oasis:names:tc:xacml:1.0:function:x500Name-one-and-only + + +mandatory/IIC042/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:date-equal +urn:oasis:names:tc:xacml:1.0:function:date-one-and-only + + +mandatory/IIC043/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:date-equal +urn:oasis:names:tc:xacml:1.0:function:date-one-and-only + + +mandatory/IIC044/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:time-equal +urn:oasis:names:tc:xacml:1.0:function:time-one-and-only + + +mandatory/IIC045/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:time-equal +urn:oasis:names:tc:xacml:1.0:function:time-one-and-only + + +mandatory/IIC046/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-equal +urn:oasis:names:tc:xacml:1.0:function:dateTime-one-and-only + + +mandatory/IIC047/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-equal +urn:oasis:names:tc:xacml:1.0:function:dateTime-one-and-only + +mandatory/IIC048/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:hexBinary-equal +urn:oasis:names:tc:xacml:1.0:function:hexBinary-one-and-only + +mandatory/IIC049/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:hexBinary-equal +urn:oasis:names:tc:xacml:1.0:function:hexBinary-one-and-only + +mandatory/IIC050/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:base64Binary-equal +urn:oasis:names:tc:xacml:1.0:function:base64Binary-one-and-only + +mandatory/IIC051/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:base64Binary-equal +urn:oasis:names:tc:xacml:1.0:function:base64Binary-one-and-only + +mandatory/IIC056/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:or +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only +urn:oasis:names:tc:xacml:1.0:function:string-regexp-match + +mandatory/IIC057/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:or +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only +urn:oasis:names:tc:xacml:1.0:function:string-regexp-match + +mandatory/IIC058/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract + +mandatory/IIC059/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract + +mandatory/IIC060/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-greater-than +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only +urn:oasis:names:tc:xacml:1.0:function:double-subtract + +mandatory/IIC061/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-greater-than +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only +urn:oasis:names:tc:xacml:1.0:function:double-subtract + +mandatory/IIC062/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:string-greater-than +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIC063/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:string-greater-than +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIC064/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:date-greater-than +urn:oasis:names:tc:xacml:1.0:function:date-one-and-only + +mandatory/IIC065/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:date-greater-than +urn:oasis:names:tc:xacml:1.0:function:date-one-and-only + +mandatory/IIC066/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:time-greater-than +urn:oasis:names:tc:xacml:1.0:function:time-one-and-only + +mandatory/IIC067/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:time-greater-than +urn:oasis:names:tc:xacml:1.0:function:time-one-and-only + +mandatory/IIC068/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-greater-than +urn:oasis:names:tc:xacml:1.0:function:dateTime-one-and-only + +mandatory/IIC069/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-greater-than +urn:oasis:names:tc:xacml:1.0:function:dateTime-one-and-only + +mandatory/IIC070/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract + +mandatory/IIC071/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract + +mandatory/IIC072/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only +urn:oasis:names:tc:xacml:1.0:function:double-subtract + +mandatory/IIC073/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only +urn:oasis:names:tc:xacml:1.0:function:double-subtract + +mandatory/IIC074/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:string-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIC075/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:string-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIC076/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:date-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:date-one-and-only + +mandatory/IIC077/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:date-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:date-one-and-only + +mandatory/IIC078/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:time-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:time-one-and-only + +mandatory/IIC079/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:time-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:time-one-and-only + +mandatory/IIC080/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:dateTime-one-and-only + +mandatory/IIC081/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:dateTime-one-and-only + +mandatory/IIC082/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-match +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-one-and-only + +mandatory/IIC083/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-match +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-one-and-only + +mandatory/IIC084/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:x500Name-match +urn:oasis:names:tc:xacml:1.0:function:x500Name-one-and-only + +mandatory/IIC085/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:x500Name-match +urn:oasis:names:tc:xacml:1.0:function:x500Name-one-and-only + +mandatory/IIC086/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:and +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIC087/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:and +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIC090/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:or +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIC091/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:or +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIC094/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:n-of +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIC095/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:n-of +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIC100/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-normalize-space +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIC101/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-normalize-to-lower-case +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIC102/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-equal +urn:oasis:names:tc:xacml:1.0:function:dateTime-one-and-only + +mandatory/IIC103/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-equal +urn:oasis:names:tc:xacml:1.0:function:dateTime-one-and-only + +mandatory/IIC104/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-equal +urn:oasis:names:tc:xacml:1.0:function:dateTime-one-and-only + +mandatory/IIC105/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-equal +urn:oasis:names:tc:xacml:1.0:function:dateTime-one-and-only + +mandatory/IIC106/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:date-equal +urn:oasis:names:tc:xacml:1.0:function:date-one-and-only + +mandatory/IIC107/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:date-equal +urn:oasis:names:tc:xacml:1.0:function:date-one-and-only + +mandatory/IIC108/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:string-less-than +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIC109/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:string-less-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIC110/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-less-than +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only + +mandatory/IIC111/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-less-than +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only + +mandatory/IIC112/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-less-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only + +mandatory/IIC113/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-less-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only + +mandatory/IIC114/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:time-less-than +urn:oasis:names:tc:xacml:1.0:function:time-one-and-only + +mandatory/IIC115/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:time-less-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:time-one-and-only + +mandatory/IIC116/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-less-than +urn:oasis:names:tc:xacml:1.0:function:dateTime-one-and-only + +mandatory/IIC117/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-less-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:dateTime-one-and-only + +mandatory/IIC118/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:date-less-than +urn:oasis:names:tc:xacml:1.0:function:date-one-and-only + +mandatory/IIC119/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:date-less-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:date-one-and-only + +mandatory/IIC120/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:string-bag-size + +mandatory/IIC121/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:string-bag +urn:oasis:names:tc:xacml:1.0:function:string-bag-size +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIC123/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:boolean-bag-size +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC124/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:boolean-is-in + +mandatory/IIC125/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:boolean-bag +urn:oasis:names:tc:xacml:1.0:function:boolean-bag-size +urn:oasis:names:tc:xacml:1.0:function:boolean-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC126/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-bag-size +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC127/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-is-in + +mandatory/IIC128/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-bag +urn:oasis:names:tc:xacml:1.0:function:integer-bag-size +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only + +mandatory/IIC129/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-bag-size +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC130/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-is-in + +mandatory/IIC131/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-bag +urn:oasis:names:tc:xacml:1.0:function:double-bag-size +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC132/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:date-bag-size +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC133/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:date-is-in + +mandatory/IIC134/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:date-bag +urn:oasis:names:tc:xacml:1.0:function:date-bag-size +urn:oasis:names:tc:xacml:1.0:function:date-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC135/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:time-bag-size + +mandatory/IIC136/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:time-is-in + +mandatory/IIC137/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:time-bag +urn:oasis:names:tc:xacml:1.0:function:time-bag-size +urn:oasis:names:tc:xacml:1.0:function:time-one-and-only + +mandatory/IIC138/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-bag-size +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC139/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-is-in + +mandatory/IIC140/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-bag +urn:oasis:names:tc:xacml:1.0:function:dateTime-bag-size +urn:oasis:names:tc:xacml:1.0:function:dateTime-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC141/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:anyURI-bag-size +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC142/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:anyURI-is-in + +mandatory/IIC143/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:anyURI-bag +urn:oasis:names:tc:xacml:1.0:function:anyURI-bag-size +urn:oasis:names:tc:xacml:1.0:function:anyURI-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC144/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:hexBinary-bag-size +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC145/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:hexBinary-is-in + +mandatory/IIC146/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:hexBinary-bag +urn:oasis:names:tc:xacml:1.0:function:hexBinary-bag-size +urn:oasis:names:tc:xacml:1.0:function:hexBinary-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC147/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:base64Binary-bag-size +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC148/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:base64Binary-is-in + +mandatory/IIC149/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:base64Binary-bag +urn:oasis:names:tc:xacml:1.0:function:base64Binary-bag-size +urn:oasis:names:tc:xacml:1.0:function:base64Binary-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC158/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:x500Name-bag-size + +mandatory/IIC159/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:x500Name-is-in + +mandatory/IIC160/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:x500Name-bag +urn:oasis:names:tc:xacml:1.0:function:x500Name-bag-size +urn:oasis:names:tc:xacml:1.0:function:x500Name-one-and-only + +mandatory/IIC161/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-bag-size + +mandatory/IIC162/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-is-in + +mandatory/IIC163/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-bag +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-bag-size +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-one-and-only + +mandatory/IIC165/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:string-regexp-match + +mandatory/IIC166/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:string-bag +urn:oasis:names:tc:xacml:1.0:function:string-regexp-match + +mandatory/IIC167/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:all-of-any +urn:oasis:names:tc:xacml:1.0:function:string-bag +urn:oasis:names:tc:xacml:1.0:function:string-regexp-match + +mandatory/IIC168/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:any-of-all +urn:oasis:names:tc:xacml:1.0:function:string-bag +urn:oasis:names:tc:xacml:1.0:function:string-regexp-match + +mandatory/IIC169/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:all-of-all +urn:oasis:names:tc:xacml:1.0:function:string-bag +urn:oasis:names:tc:xacml:1.0:function:string-regexp-match + +mandatory/IIC170/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-normalize-space + +mandatory/IIC171/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:string-bag +urn:oasis:names:tc:xacml:1.0:function:string-bag-size +urn:oasis:names:tc:xacml:1.0:function:string-intersection + +mandatory/IIC172/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:string-at-least-one-member-of +urn:oasis:names:tc:xacml:1.0:function:string-bag + +mandatory/IIC173/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:string-bag +urn:oasis:names:tc:xacml:1.0:function:string-bag-size +urn:oasis:names:tc:xacml:1.0:function:string-union + +mandatory/IIC174/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:string-bag +urn:oasis:names:tc:xacml:1.0:function:string-subset + +mandatory/IIC175/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:string-bag +urn:oasis:names:tc:xacml:1.0:function:string-set-equals + +mandatory/IIC176/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:boolean-bag +urn:oasis:names:tc:xacml:1.0:function:boolean-bag-size +urn:oasis:names:tc:xacml:1.0:function:boolean-intersection +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC177/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:boolean-at-least-one-member-of +urn:oasis:names:tc:xacml:1.0:function:boolean-bag + +mandatory/IIC178/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:boolean-bag +urn:oasis:names:tc:xacml:1.0:function:boolean-bag-size +urn:oasis:names:tc:xacml:1.0:function:boolean-union +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC179/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:boolean-bag +urn:oasis:names:tc:xacml:1.0:function:boolean-subset + +mandatory/IIC180/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:boolean-bag +urn:oasis:names:tc:xacml:1.0:function:boolean-set-equals + +mandatory/IIC181/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-bag +urn:oasis:names:tc:xacml:1.0:function:integer-bag-size +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:integer-intersection + +mandatory/IIC182/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-at-least-one-member-of +urn:oasis:names:tc:xacml:1.0:function:integer-bag + +mandatory/IIC183/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-bag +urn:oasis:names:tc:xacml:1.0:function:integer-bag-size +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:integer-union + +mandatory/IIC184/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-bag +urn:oasis:names:tc:xacml:1.0:function:integer-subset + +mandatory/IIC185/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-bag +urn:oasis:names:tc:xacml:1.0:function:integer-set-equals + +mandatory/IIC186/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-bag +urn:oasis:names:tc:xacml:1.0:function:double-bag-size +urn:oasis:names:tc:xacml:1.0:function:double-intersection +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC187/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-at-least-one-member-of +urn:oasis:names:tc:xacml:1.0:function:double-bag + +mandatory/IIC188/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-bag +urn:oasis:names:tc:xacml:1.0:function:double-bag-size +urn:oasis:names:tc:xacml:1.0:function:double-union +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC189/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-bag +urn:oasis:names:tc:xacml:1.0:function:double-subset + +mandatory/IIC190/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-bag +urn:oasis:names:tc:xacml:1.0:function:double-set-equals + +mandatory/IIC191/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:date-bag +urn:oasis:names:tc:xacml:1.0:function:date-bag-size +urn:oasis:names:tc:xacml:1.0:function:date-intersection +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC192/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:date-at-least-one-member-of +urn:oasis:names:tc:xacml:1.0:function:date-bag + +mandatory/IIC193/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:date-bag +urn:oasis:names:tc:xacml:1.0:function:date-bag-size +urn:oasis:names:tc:xacml:1.0:function:date-union +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC194/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:date-bag +urn:oasis:names:tc:xacml:1.0:function:date-subset + +mandatory/IIC195/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:date-bag +urn:oasis:names:tc:xacml:1.0:function:date-set-equals + +mandatory/IIC196/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:time-bag +urn:oasis:names:tc:xacml:1.0:function:time-bag-size +urn:oasis:names:tc:xacml:1.0:function:time-intersection + +mandatory/IIC197/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:time-at-least-one-member-of +urn:oasis:names:tc:xacml:1.0:function:time-bag + +mandatory/IIC198/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:time-bag +urn:oasis:names:tc:xacml:1.0:function:time-bag-size +urn:oasis:names:tc:xacml:1.0:function:time-union + +mandatory/IIC199/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:time-bag +urn:oasis:names:tc:xacml:1.0:function:time-subset + +mandatory/IIC200/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:time-bag +urn:oasis:names:tc:xacml:1.0:function:time-set-equals + +mandatory/IIC201/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-bag +urn:oasis:names:tc:xacml:1.0:function:dateTime-bag-size +urn:oasis:names:tc:xacml:1.0:function:dateTime-intersection +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC202/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-at-least-one-member-of +urn:oasis:names:tc:xacml:1.0:function:dateTime-bag + +mandatory/IIC203/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-bag +urn:oasis:names:tc:xacml:1.0:function:dateTime-bag-size +urn:oasis:names:tc:xacml:1.0:function:dateTime-union +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC204/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-bag +urn:oasis:names:tc:xacml:1.0:function:dateTime-subset + +mandatory/IIC205/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:dateTime-bag +urn:oasis:names:tc:xacml:1.0:function:dateTime-set-equals + +mandatory/IIC206/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:anyURI-bag +urn:oasis:names:tc:xacml:1.0:function:anyURI-bag-size +urn:oasis:names:tc:xacml:1.0:function:anyURI-intersection +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC207/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:anyURI-at-least-one-member-of +urn:oasis:names:tc:xacml:1.0:function:anyURI-bag + +mandatory/IIC208/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:anyURI-bag +urn:oasis:names:tc:xacml:1.0:function:anyURI-bag-size +urn:oasis:names:tc:xacml:1.0:function:anyURI-union +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC209/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:anyURI-bag +urn:oasis:names:tc:xacml:1.0:function:anyURI-subset + +mandatory/IIC210/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:anyURI-bag +urn:oasis:names:tc:xacml:1.0:function:anyURI-set-equals + +mandatory/IIC211/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:x500Name-bag +urn:oasis:names:tc:xacml:1.0:function:x500Name-bag-size +urn:oasis:names:tc:xacml:1.0:function:x500Name-intersection + +mandatory/IIC212/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:x500Name-at-least-one-member-of +urn:oasis:names:tc:xacml:1.0:function:x500Name-bag + +mandatory/IIC213/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:x500Name-bag +urn:oasis:names:tc:xacml:1.0:function:x500Name-bag-size +urn:oasis:names:tc:xacml:1.0:function:x500Name-union + +mandatory/IIC214/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:x500Name-bag +urn:oasis:names:tc:xacml:1.0:function:x500Name-subset + +mandatory/IIC215/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:x500Name-bag +urn:oasis:names:tc:xacml:1.0:function:x500Name-set-equals + +mandatory/IIC216/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-bag +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-bag-size +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-intersection + +mandatory/IIC217/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-at-least-one-member-of +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-bag + +mandatory/IIC218/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-equal +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-bag +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-bag-size +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-union + +mandatory/IIC219/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-bag +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-subset + +mandatory/IIC220/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-bag +urn:oasis:names:tc:xacml:1.0:function:rfc822Name-set-equals + +mandatory/IIC221/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:hexBinary-bag +urn:oasis:names:tc:xacml:1.0:function:hexBinary-bag-size +urn:oasis:names:tc:xacml:1.0:function:hexBinary-intersection +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC222/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:hexBinary-at-least-one-member-of +urn:oasis:names:tc:xacml:1.0:function:hexBinary-bag + +mandatory/IIC223/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:hexBinary-bag +urn:oasis:names:tc:xacml:1.0:function:hexBinary-bag-size +urn:oasis:names:tc:xacml:1.0:function:hexBinary-union +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC224/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:hexBinary-bag +urn:oasis:names:tc:xacml:1.0:function:hexBinary-subset + +mandatory/IIC225/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:hexBinary-bag +urn:oasis:names:tc:xacml:1.0:function:hexBinary-set-equals + +mandatory/IIC226/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:base64Binary-bag +urn:oasis:names:tc:xacml:1.0:function:base64Binary-bag-size +urn:oasis:names:tc:xacml:1.0:function:base64Binary-intersection +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC227/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:base64Binary-at-least-one-member-of +urn:oasis:names:tc:xacml:1.0:function:base64Binary-bag + +mandatory/IIC228/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:base64Binary-bag +urn:oasis:names:tc:xacml:1.0:function:base64Binary-bag-size +urn:oasis:names:tc:xacml:1.0:function:base64Binary-union +urn:oasis:names:tc:xacml:1.0:function:integer-equal + +mandatory/IIC229/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:base64Binary-bag +urn:oasis:names:tc:xacml:1.0:function:base64Binary-subset + +mandatory/IIC230/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:base64Binary-bag +urn:oasis:names:tc:xacml:1.0:function:base64Binary-set-equals + +mandatory/IIC350/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-equal +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only + +mandatory/IIC351/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-equal +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only + +mandatory/IIC352/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-equal +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only + +mandatory/IIC353/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-equal +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only + +mandatory/IIC354/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-equal +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only + +mandatory/IIC355/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-equal +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only + +mandatory/IIC356/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-less-than +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only + +mandatory/IIC357/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-greater-than +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only + +mandatory/IIC358/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-add +urn:oasis:names:tc:xacml:1.0:function:double-equal +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only + +mandatory/IIC359/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:double-equal +urn:oasis:names:tc:xacml:1.0:function:double-one-and-only +urn:oasis:names:tc:xacml:1.0:function:double-subtract + +mandatory/IID001/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IID002/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID003/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IID004/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID005/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IID006/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID007/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IID008/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID009/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID010/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID011/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IID012/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID013/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID014/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID015/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IID016/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID017/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IID018/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID019/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IID020/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID021/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IID022/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID023/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IID024/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID025/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IID026/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-less-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID027/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-less-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID028/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-less-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID300/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID301/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IID302/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID303/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID304/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IID305/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID306/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IID307/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID308/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID309/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IID310/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID311/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID312/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID313/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID314/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IID315/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID316/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID317/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID318/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID319/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IID320/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID330/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID331/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID332/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID333/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID340/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID341/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID342/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IID343/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIF311/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA001/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA002/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA003/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA004/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA005/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA006/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA007/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA008/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA009/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA010/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA011/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA012/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA013/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA014/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA015/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA016/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA017/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA018/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA019/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA020/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA021/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA022/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA023/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA024/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA025/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA026/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-less-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA027/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-less-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA028/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-less-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA301/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA302/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA303/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA304/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA305/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA306/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA307/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA308/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA309/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA310/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA311/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA312/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA313/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA314/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA315/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA316/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA317/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA318/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA319/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA320/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA321/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA322/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA323/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA324/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA325/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal + +mandatory/IIIA326/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-less-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA327/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-less-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA328/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-less-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal +urn:oasis:names:tc:xacml:1.0:function:string-one-and-only + +mandatory/IIIA329/Policy.xml: +urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal +urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only +urn:oasis:names:tc:xacml:1.0:function:integer-subtract +urn:oasis:names:tc:xacml:1.0:function:string-equal diff --git a/benchmarks/hyperfine-iia001.json b/benchmarks/hyperfine-iia001.json new file mode 100644 index 0000000..5cfd002 --- /dev/null +++ b/benchmarks/hyperfine-iia001.json @@ -0,0 +1,212 @@ +{ + "results": [ + { + "command": "authzforce", + "mean": 1.8461527814999996, + "stddev": 0.06199174539502622, + "median": 1.8238858158, + "user": 5.36704266, + "system": 0.20038110000000003, + "min": 1.7681575743, + "max": 1.9531087263, + "times": [ + 1.7985675612999998, + 1.8072159603, + 1.7681575743, + 1.8040717123, + 1.8547239183, + 1.9046467713, + 1.8049998702999999, + 1.8405556713, + 1.9531087263, + 1.9254800493 + ], + "exit_codes": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "command": "lean", + "mean": 4.419457606, + "stddev": 0.008869787618510696, + "median": 4.417610675300001, + "user": 4.370591760000001, + "system": 0.052795999999999996, + "min": 4.4061337973, + "max": 4.4311239923, + "times": [ + 4.4094097333, + 4.4160989583, + 4.4191223923, + 4.4280726193, + 4.4061337973, + 4.4246227593, + 4.4309326733, + 4.4138470893, + 4.4152120453000006, + 4.4311239923 + ], + "exit_codes": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "command": "opa", + "mean": 0.04686065166507937, + "stddev": 0.0007439499827213784, + "median": 0.046807240300000004, + "user": 0.04948119015873017, + "system": 0.009103655555555559, + "min": 0.04563805730000001, + "max": 0.04922981230000001, + "times": [ + 0.0461474123, + 0.048303486300000004, + 0.04922981230000001, + 0.04705487430000001, + 0.047513765300000003, + 0.047122320300000006, + 0.0468518003, + 0.046828386300000004, + 0.04866176530000001, + 0.04631246530000001, + 0.04743980330000001, + 0.04692121330000001, + 0.046232237300000006, + 0.04820853530000001, + 0.046098580300000004, + 0.0464998053, + 0.046051025300000006, + 0.04594847430000001, + 0.0466571013, + 0.047440779300000006, + 0.04737457230000001, + 0.04633055130000001, + 0.048487699300000006, + 0.04748818430000001, + 0.047259265300000006, + 0.0467570813, + 0.046098668300000006, + 0.04598046630000001, + 0.04675927230000001, + 0.0469496723, + 0.0461157873, + 0.046176294300000004, + 0.0473107253, + 0.0468981113, + 0.0460657043, + 0.045878819300000005, + 0.0476590813, + 0.046807240300000004, + 0.04664132830000001, + 0.046108756300000005, + 0.046206166300000004, + 0.046065450300000005, + 0.04714411030000001, + 0.048273055300000006, + 0.04725586130000001, + 0.04637673330000001, + 0.04669826330000001, + 0.04711734730000001, + 0.0476596763, + 0.046422681300000004, + 0.047071346300000004, + 0.0469502373, + 0.046924527300000005, + 0.04647903330000001, + 0.046374657300000004, + 0.046936907300000004, + 0.046474964300000005, + 0.04658955630000001, + 0.046119356300000004, + 0.046911354300000006, + 0.0464168043, + 0.047443984300000006, + 0.04563805730000001 + ], + "exit_codes": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + } + ] +} diff --git a/benchmarks/hyperfine-iia003.json b/benchmarks/hyperfine-iia003.json new file mode 100644 index 0000000..ecc7a79 --- /dev/null +++ b/benchmarks/hyperfine-iia003.json @@ -0,0 +1,208 @@ +{ + "results": [ + { + "command": "authzforce", + "mean": 1.8539233053999997, + "stddev": 0.07045118765524386, + "median": 1.8637640012, + "user": 5.5190032, + "system": 0.19728234, + "min": 1.7220111481999998, + "max": 1.9277803882, + "times": [ + 1.7220111481999998, + 1.7490110442, + 1.8364869041999998, + 1.8772167472, + 1.8431721002, + 1.9068409922, + 1.9116545762, + 1.8503112552, + 1.9147478982, + 1.9277803882 + ], + "exit_codes": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "command": "lean", + "mean": 4.419570566399999, + "stddev": 0.010926697857862277, + "median": 4.4211140677, + "user": 4.3713518, + "system": 0.052455339999999996, + "min": 4.4019222472, + "max": 4.4339212692, + "times": [ + 4.4339212692, + 4.4114070332, + 4.416890663199999, + 4.4229281052, + 4.425064122199999, + 4.4252808622, + 4.4193000302, + 4.4051925292, + 4.4337988022, + 4.4019222472 + ], + "exit_codes": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "command": "opa", + "mean": 0.04684904405245902, + "stddev": 0.0007265745663278671, + "median": 0.046686584200000006, + "user": 0.04951623770491803, + "system": 0.008924961311475412, + "min": 0.04590612720000001, + "max": 0.04947239020000001, + "times": [ + 0.047505085200000005, + 0.0477891012, + 0.04766807220000001, + 0.04757789120000001, + 0.046627629200000006, + 0.046532016200000005, + 0.04672034220000001, + 0.0460801522, + 0.04666791320000001, + 0.046594200200000005, + 0.047600413200000004, + 0.0461862882, + 0.046681552200000004, + 0.04754236220000001, + 0.04673284120000001, + 0.047990504200000006, + 0.04669201320000001, + 0.046056508200000006, + 0.046408807200000006, + 0.047217328200000006, + 0.047256917200000005, + 0.046044935200000005, + 0.045964099200000004, + 0.04947239020000001, + 0.047289161200000006, + 0.046399726200000005, + 0.046341788200000004, + 0.046582481200000005, + 0.04590612720000001, + 0.046078393200000005, + 0.047378041200000005, + 0.046084784200000006, + 0.047149540200000006, + 0.046272840200000005, + 0.04670162420000001, + 0.046520495200000005, + 0.04646542520000001, + 0.047481608200000004, + 0.048442480200000006, + 0.046686584200000006, + 0.045997991200000005, + 0.047016423200000004, + 0.046089728200000006, + 0.04778034120000001, + 0.0489142242, + 0.04689554320000001, + 0.046330581200000005, + 0.0460137752, + 0.0473294802, + 0.046463515200000007, + 0.0472964062, + 0.0465713462, + 0.046739780200000004, + 0.047043988200000005, + 0.0468881052, + 0.0469259912, + 0.0463439402, + 0.046318177200000005, + 0.046465140200000005, + 0.046179928200000005, + 0.04679681820000001 + ], + "exit_codes": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + } + ] +} diff --git a/benchmarks/hyperfine-iia006.json b/benchmarks/hyperfine-iia006.json new file mode 100644 index 0000000..7d8d698 --- /dev/null +++ b/benchmarks/hyperfine-iia006.json @@ -0,0 +1,206 @@ +{ + "results": [ + { + "command": "authzforce", + "mean": 1.8722544155799998, + "stddev": 0.0448476189551403, + "median": 1.87713420668, + "user": 5.29085678, + "system": 0.19428865999999995, + "min": 1.8023647006799999, + "max": 1.93418314468, + "times": [ + 1.91022297268, + 1.8098531996799998, + 1.87232539068, + 1.8023647006799999, + 1.83828486468, + 1.90194070568, + 1.91359825268, + 1.88194302268, + 1.93418314468, + 1.85782790168 + ], + "exit_codes": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "command": "lean", + "mean": 4.53456651428, + "stddev": 0.009934426084958611, + "median": 4.53884667318, + "user": 4.48431508, + "system": 0.05463736, + "min": 4.518855267679999, + "max": 4.54707742168, + "times": [ + 4.53892170468, + 4.54263477868, + 4.52490095668, + 4.54707742168, + 4.5387716416799995, + 4.540713494679999, + 4.52622729668, + 4.54329805368, + 4.52426452668, + 4.518855267679999 + ], + "exit_codes": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + }, + { + "command": "opa", + "mean": 0.04826780581333333, + "stddev": 0.0009917655763182548, + "median": 0.04805647418, + "user": 0.050686930000000005, + "system": 0.009130410000000002, + "min": 0.04688597268, + "max": 0.051628061680000004, + "times": [ + 0.04802554868, + 0.04710740268, + 0.04863815768, + 0.048210658680000004, + 0.04965373968, + 0.05114789668, + 0.048087399680000004, + 0.04963996468, + 0.04848601568, + 0.04776453168, + 0.047728559680000004, + 0.04891648668, + 0.04876128368, + 0.04833371168, + 0.04959416168, + 0.04831524168, + 0.04784011068, + 0.04791020968, + 0.04737187868, + 0.048367496680000004, + 0.04715601768, + 0.04828764868, + 0.04840128568, + 0.04751085468, + 0.04908777768, + 0.04972917968, + 0.04848996868, + 0.04743947068, + 0.04810144268, + 0.04880705868, + 0.05105722568, + 0.04761976368, + 0.04743746368, + 0.04802172868, + 0.04780610868, + 0.04784965268, + 0.047334945680000004, + 0.04755185368, + 0.04794043268, + 0.04697354768, + 0.04813416268, + 0.04743428468, + 0.04769424868, + 0.04976519068, + 0.04848638568, + 0.051628061680000004, + 0.04754968568, + 0.04715066668, + 0.04769493568, + 0.04880571868, + 0.04883541968, + 0.04823892868, + 0.04769713568, + 0.04727608968, + 0.04817077868, + 0.04893817868, + 0.04800505268, + 0.04767638868, + 0.04749717868, + 0.04688597268 + ], + "exit_codes": [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + } + ] +} diff --git a/benchmarks/lean-harness.bash b/benchmarks/lean-harness.bash new file mode 100644 index 0000000..e59b3da --- /dev/null +++ b/benchmarks/lean-harness.bash @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +COMPILE_REQUEST="../xacml-proofs/compiler/_build/default/bin/request.exe" +COMPILE_POLICY="../xacml-proofs/compiler/_build/default/bin/main.exe" + +cat Xacml.lean <($COMPILE_REQUEST $1/Request.xml) <($COMPILE_POLICY $1/Policy.xml) > /tmp/test.lean +lean /tmp/test.lean diff --git a/benchmarks/rego-harness.bash b/benchmarks/rego-harness.bash new file mode 100644 index 0000000..48dbc5d --- /dev/null +++ b/benchmarks/rego-harness.bash @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +NAME="$(basename $1)" +if [ $NAME = "IIA001" ]; then + NAME="iia1" +elif [ $NAME = "IIA003" ]; then + NAME="iia003" +elif [ $NAME = "IIA006" ]; then + NAME="iia006" +fi + +opa eval -f raw --data rego/$NAME.rego -i rego/$NAME.json 'data.equivalence.allow' diff --git a/benchmarks/rego/iia003.json b/benchmarks/rego/iia003.json new file mode 100644 index 0000000..660d7c1 --- /dev/null +++ b/benchmarks/rego/iia003.json @@ -0,0 +1 @@ +{"request": [{"category":"urn:oasis:names:tc:xacml:1.0:subject-category:access-subject","identifier":"urn:oasis:names:tc:xacml:1.0:subject:subject-id","value":{"kind":"primitive","type":"http://www.w3.org/2001/XMLSchema#string","value":"Julius Hibbert"}},{"category":"urn:oasis:names:tc:xacml:3.0:attribute-category:resource","identifier":"urn:oasis:names:tc:xacml:1.0:resource:resource-id","value":{"kind":"primitive","type":"http://www.w3.org/2001/XMLSchema#anyURI","value":"http://medico.com/record/patient/BartSimpson"}},{"category":"urn:oasis:names:tc:xacml:3.0:attribute-category:action","identifier":"urn:oasis:names:tc:xacml:1.0:action:action-id","value":{"kind":"primitive","type":"http://www.w3.org/2001/XMLSchema#string","value":"read"}}]} diff --git a/benchmarks/rego/iia003.rego b/benchmarks/rego/iia003.rego new file mode 100644 index 0000000..87482c8 --- /dev/null +++ b/benchmarks/rego/iia003.rego @@ -0,0 +1,815 @@ +package equivalence + +import future.keywords.every +import future.keywords.if +import future.keywords.in + +######################################################################## +# Data Types +######################################################################## + +## MatchResult + +# - is_match => { "match_result": true } +# - no_match => { "match_result": false } +# - indeterminate => { "match_result": "indeterminate" } + +## Decision + +# - permit => { "decision": "permit" } +# - deny => { "decision": "deny" } +# - not_applicable => { "decision": "not_applicable" } +# - indeterminate => { "decision": "indeterminate" } + +## Extended Decision + +# - permit => { "decision_extended": "permit" } +# - deny => { "decision_extended": "deny" } +# - not_applicable => { "decision_extended": "not_applicable" } +# - indeterminate => { "decision_extended": "indeterminate" } +# - indeterminate_d => { "decision_extended": "indeterminate_d" } +# - indeterminate_p => { "decision_extended": "indeterminate_p" } +# - indeterminate_dp => { "decision_extended": "indeterminate_dp" } + +lift_decision_indeterminate({ "decision": "not_applicable" }) := { "decision": "not_applicable" } +lift_decision_indeterminate({ "decision": "permit" }) := { "decision": "indeterminate_p" } +lift_decision_indeterminate({ "decision": "deny" }) := { "decision": "indeterminate_d" } +lift_decision_indeterminate({ "decision": "indeterminate" }) := { "decision": "indeterminate_dp" } +lift_decision_indeterminate({ "decision": "indeterminate_dp" }) := { "decision": "indeterminate_dp" } +lift_decision_indeterminate({ "decision": "indeterminate_p" }) := { "decision": "indeterminate_p" } +lift_decision_indeterminate({ "decision": "indeterminate_d" }) := { "decision": "indeterminate_d" } + +## Value + +# - { "kind": "primitive", +# "type": string, +# "value": string } +# - { "kind": "bag", +# "values": ... } + +### Booleans + +true_value := { "kind": "primitive", "type": "boolean", "value": true } +false_value := { "kind": "primitive", "type": "boolean", "value": false } +indeterminate_value := { "kind": "primitive", "type": "boolean" } + +is_indeterminate(value) if { is_null(value.value) } + +## StatusCode + +# - ok => { "status": "ok" } +# - missing_attribute => { "status": "missing_attribute" } +# - syntax_error => { "status": "syntax_error" } +# - processing_error => { "status": "processing_error" } + +## AttributeDesignator + +# - { category : string +# identifier : string +# type : string +# issuer : string or null +# must_be_present : boolean } + +## Expression + +# - { "expression": "apply", +# "function": string, +# "args": [string, ...] } +# - { "expression": "attribute_designator", +# "inner": AttributeDesignator } +# - { "expression": "attribute_value", +# "inner": Value } +# - { "expression": "function" +# "function": string } + +## Match + +# - { "function": string, +# "designator": AttributeDesignator, +# "value": Value } + +## Obligation + +# - { "assignments": [Attribute, ...], +# "identifier": string } + +## ObligationExpression + +# - { "assignments": [AttributeAssignmentExpression, ...], +# "identifier": string, +# "fulfill_on": Decision } + +## Advice + +# - { "assignments": [Attribute, ...], +# "identifier": string } + +## AdviceExpression + +# - { "assignments": [AttributeAssignmentExpression, ...], +# "identifier": string, +# "applies_to": Decision } + +## AttributeAssignmentExpression + +# - { "category": string, +# "identifier": string, +# "issuer": string or null, +# "expression": Expression } + +## Target: [[[Expression, ...], ...], ...] + +## Rule + +# - { "target": Target, +# "condition": Expression or null, +# "effect": "permit" or "deny", +# "obligations": [ObligationExpression, ...], +# "advice": [AdviceExpression, ...] } + +## Policy + +# - { "combinator": string, +# "target": Target, +# "obligations": [ObligationExpression, ...], +# "advice": [AdviceExpression, ...] } + +## PolicySet + +# - { "combinator": string, +# "target": Target, +# "obligations": [ObligationExpression, ...], +# "advice": [AdviceExpression, ...] } + +# We assume the request attributes are stored in `input.request` as an array or set of +# +# { category : string +# identifier : string +# issuer : string or null +# value : [Value, ...] } + +######################################################################## +# Match Functions +######################################################################## + +apply_xacml_function( + "urn:oasis:names:tc:xacml:1.0:function:string-equal", + [{ "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": a }, + { "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": b }]) := true_value if { + a == b +} else := false_value +apply_xacml_function( + "urn:oasis:names:tc:xacml:1.0:function:anyURI-equal", + [{ "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#anyURI", + "value": a }, + { "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#anyURI", + "value": b }]) := true_value if { + a == b +} else := false_value + +######################################################################## +# AttributeDesignator +######################################################################## + +designator_matches(designator, attribute) if { + attribute.category == designator.category + attribute.identifier == designator.identifier + attribute.value.type == designator.type + not attribute.attr.issuer +} + +designator_matches(designator, attribute) if { + attribute.category == designator.category + attribute.identifier == designator.identifier + attribute.value.type == designator.type + attribute.attr.issuer == designator.issuer +} + +evaluate_designator(designator) := { "kind": "bag", "values": xs } if { + xs := [y.value | y := input.request[_]; designator_matches(designator, y)] + count(xs) > 1 +} + +evaluate_designator(designator) := xs[0] if { + xs := [y.value | y := input.request[_]; designator_matches(designator, y)] + count(xs) == 1 +} + +evaluate_designator(designator) := { "kind": "bag", "values": xs } if { + xs := [y.value | y := input.request[_]; designator_matches(designator, y)] + count(xs) == 0 + not designator.must_be_present +} + +evaluate_designator(designator) := { "status": "missing_attribute" } if { + xs := [y.value | y := input.request[_]; designator_matches(designator, y)] + count(xs) == 0 + designator.must_be_present +} + +######################################################################### +# Match +######################################################################## + +evaluate_match(match) := { "match_result": true_value } if { + designator_result := evaluate_designator(match.designator) + + # Designator evaluates without error. + designator_result + + some x in designator_result.values + apply_xacml_function(match.function, [x, match.value]).value == true +} else := { "match_result": true_value } if { + designator_result := evaluate_designator(match.designator) + + # Designator evaluates without error. + designator_result + + apply_xacml_function(match.function, [designator_result, match.value]).value == true +} else := { "match_result": indeterminate_value } if { + designator_result := evaluate_designator(match.designator) + + # Designator evaluates without error. + designator_result + + some x in designator_result + is_indeterminate(apply_xacml_function(match.function, [x, match.value])) +} else := { "match_result": false_value } if { + designator_result := evaluate_designator(match.designator) + + # Designator evaluates without error. + designator_result +} else := { "match_result": indeterminate_value } + +# Last case runs when evaluating the designator results in an error. + +evaluate_all_of(conj) := { "match_result": true_value } if { + every x in conj { + evaluate_match(x).match_result.value == true + } +} else := { "match_result": "indeterminate" } if { + some x in conj + is_indeterminate(evaluate_match(x).match_result) +} else := { "match_result": "no_match" } + +evaluate_any_of([]) := { "match_result": true_value } +evaluate_any_of(disj) := { "match_result": true_value } if { + some x in disj + evaluate_all_of(x) == { "match_result": true_value } +} else := { "match_result": "indeterminate" } if { + some x in disj + evaluate_all_of(x) == { "match_result": true_value } +} else := { "match_result": "no_match" } + + +######################################################################## +# Target +######################################################################## + +evaluate_target([]) := { "match_result": true_value } +evaluate_target(xs) := { "match_result": true_value } if { + every disj in xs { + evaluate_any_of(disj).match_result.value == true + } +} else := { "match_result": false_value } if { + some disj in xs + evaluate_any_of(disj).match_result == "no_match" +} else := { "match_result": indeterminate_value } + +######################################################################## +# Expression +######################################################################## + +evaluate_expression({ "expression": "apply", "function": function_name, "args": args }) := x if { + x := apply_xacml_function(function_name, args) +} +evaluate_expression({ "expression": "attribute_designator", "inner": designator }) := x if { + x := evaluate_designator(designator) +} +evaluate_expression({ "expression": "attribute_value", "inner": value }) := x if { + x := value +} +evaluate_expression({ "expression": "function", "function": name }) := x if { + x := name +} + +######################################################################## +# Obligations and Advice +######################################################################## + +evaluate_attribute_assignment_expression(expr) := assignment { + { "kind": "primitive", "value": inner } = evaluate_expression(expr.expression) + assignment := { "category": expr.category, + "identifier": expr.identifier, + "issuer": expr.issuer, + "value": inner } +} + +evaluate_obligation_expression(obligation_expression) := obligation { + assignments := [evaluate_attribute_assignment_expression(expr) | expr := obligation_expression.assignments[_]] + obligation := { "assignments": assignments, "identifier": obligation_expression.identifier } +} + +evaluate_advice_expression(advice_expression) := advice { + assignments := [evaluate_attribute_assignment_expression(expr) | expr := advice_expression.assignments[_]] + advice := { "assignments": assignments, "identifier": advice_expression.identifier } +} + + +######################################################################## +# Rule +######################################################################## + +# Condition is specified and applicable +evaluate_rule_decision(rule) := { "decision_extended": decision } { + evaluate_target(rule.target).match_result.value == true + + is_object(rule.condition) + evaluate_expression(rule.condition) == true + + decision := rule.effect +} +# Condition is specified and not applicable +evaluate_rule_decision(rule) := { "decision_extended": "not_applicable" } { + evaluate_target(rule.target).match_result.value == true + evaluate_expression(rule.condition) == false +} +# Condition is indeterminate +evaluate_rule_decision(rule) := { "decision_extended": "indeterminate_p" } { + evaluate_target(rule.target).match_result.value == true + condition := evaluate_expression(rule.condition) + is_null(condition) + rule.effect == "permit" +} +evaluate_rule_decision(rule) := { "decision_extended": "indeterminate_d" } { + evaluate_target(rule.target).match_result.value == true + condition := evaluate_expression(rule.condition) + is_null(condition) + rule.effect == "deny" +} +# Condition is unspecified +evaluate_rule_decision(rule) := { "decision_extended": decision } { + evaluate_target(rule.target).match_result.value == true + decision := rule.effect +} + +evaluate_rule_decision(rule) := { "decision_extended": "not_applicable" } { + evaluate_target(rule.target).match_result.value == false +} +evaluate_rule_decision(rule) := { "decision_extended": "indeterminate_p" } { + is_indeterminate(evaluate_target(rule.target)) + rule.effect == "permit" +} +evaluate_rule_decision(rule) := { "decision_extended": "indeterminate_d" } { + is_indeterminate(evaluate_target(rule.target)) + rule.effect == "permit" +} + +evaluate_rule_advices(rule) := { "advice": advice } if { + decision := evaluate_rule_decision(rule) + advice := [expr | expr := rule.advice[_]; expr.applies_to == decision ] +} + +evaluate_rule_obligations(rule) := { "obligations": obligations } if { + decision := evaluate_rule_decision(rule) + obligations := [expr | expr := rule.obligations[_]; expr.fulfill_on == decision ] +} + +######################################################################## +# Policy +######################################################################## + +evaluate_rule_combinator("deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("ordered_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("ordered_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("deny_unless_permit", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "deny" } + +evaluate_rule_combinator("permit_unless_deny", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "permit" } + +evaluate_rule_combinator("first_applicable", results) := result if { + indices := [i | results[i].decision_extended != "not_applicable"] + count(indices) > 0 + result := results[max(indices)] + result.decision_extended == "deny" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("legacy_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("ordered_legacy_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("legacy_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("ordered_legacy_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +# child_results := [result | rule := policy.rules[_]; result := evaluate_rule_decision(rule)] +evaluate_policy_decision(policy, child_results) := decision if { + evaluate_target(policy.target).match_result.value == true + decision := evaluate_rule_combinator(policy.combinator, child_results) +} else := decision if { + is_indeterminate(evaluate_target(policy.target)) + decision := lift_decision_indeterminate(evaluate_rule_combinator(policy.combinator, child_results)) +} else := { "decision_extended": "not_applicable" } + +# children_advice := [advice | rule := policy.rules[_]; expr := evaluate_rule_advices(rule); advice := expr[_]] +evaluate_policy_advices(policy, child_results, children_advice) := { "advice" : advice } if { + decision := evaluate_policy_decision(policy, child_results) + policy_advice := [expr | expr := policy.advice[_]; expr.applies_to == decision ] + advice := array.concat(policy_advice, children_advice) +} + +# children_obligations := [obligation | rule := policy.rules[_]; expr := evaluate_rule_obligations(rule); obligation := expr[_]] +evaluate_policy_obligations(policy, child_results, children_obligations) := { "obligations" : obligations } if { + decision := evaluate_policy_decision(policy, child_results) + policy_obligations := [expr | expr := policy.obligations[_]; expr.applies_to == decision ] + obligations := array.concat(policy_obligations, children_obligations) +} + +######################################################################## +# PolicySet +######################################################################## + +evaluate_policy_combinator("deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("ordered_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("ordered_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("deny_unless_permit", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "deny" } + +evaluate_policy_combinator("permit_unless_deny", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "permit" } + +evaluate_policy_combinator("first_applicable", results) := result if { + indices := [i | results[i].decision_extended != "not_applicable"] + count(indices) > 0 + result := results[max(indices)] + result.decision_extended == "deny" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("only_one_applicable", results) := result if { + applicable := [result | result := results[i]; result.decision_extended != "not_applicable"] + count(applicable) == 1 + result := applicable[0] +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("legacy_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "indeterminate" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("ordered_legacy_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "indeterminate" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("legacy_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("ordered_legacy_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_policyset_decision(policyset, child_results) := decision if { + evaluate_target(policyset.target).match_result.value == true + decision := evaluate_policy_combinator(policyset.combinator, child_results) +} else := decision if { + is_indeterminate(evaluate_target(policyset.target)) + decision := lift_decision_indeterminate(evaluate_policy_combinator(policyset.combinator, child_results)) +} else := { "decision_extended": "not_applicable" } + +evaluate_policyset_advices(policyset, child_results, child_advice) := { "advice" : advice } if { + decision := evaluate_policyset_decision(policyset, child_results) + policyset_advice := [expr | expr := policyset.advice[_]; expr.applies_to == decision ] + advice := array.concat(policyset_advice, child_advice) +} + +evaluate_policyset_obligations(policyset, child_results, child_obligations) := { "obligations" : obligations } if { + decision := evaluate_policyset_decision(policyset, child_results) + policyset_obligations := [expr | expr := policyset.obligations[_]; expr.applies_to == decision ] + obligations := array.concat(policyset_obligations, child_obligations) +} + +IIA003_policy := { + "combinator": "deny_overrides", + "target": [], + "obligations": [], + "advice": [] +} + +IIA003_rule := { + "target": [[[{ "function": "urn:oasis:names:tc:xacml:1.0:function:string-equal", + "designator": { + "identifier": "urn:oasis:names:tc:xacml:2.0:conformance-test:attribute:bogus", + "category": "urn:oasis:names:tc:xacml:1.0:subject-category:access-subject", + "type": "http://www.w3.org/2001/XMLSchema#string", + "must_be_present": false + }, + "value": { + "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": "Physician" + }}]], + [[{ "function": "urn:oasis:names:tc:xacml:1.0:function:anyURI-equal", + "designator": { + "identifier": "urn:oasis:names:tc:xacml:1.0:resource:resource-id", + "category": "urn:oasis:names:tc:xacml:3.0:attribute-category:resource", + "type": "http://www.w3.org/2001/XMLSchema#anyURI", + "must_be_present": false + }, + "value": { + "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#anyURI", + "value": "http://medico.com/record/patient/BartSimpson" + }}]], + [[{ "function": "urn:oasis:names:tc:xacml:1.0:function:string-equal", + "designator": { + "identifier": "urn:oasis:names:tc:xacml:1.0:action:action-id", + "category": "urn:oasis:names:tc:xacml:3.0:attribute-category:action", + "type": "http://www.w3.org/2001/XMLSchema#string", + "must_be_present": false + }, + "value": { + "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": "read" + }}], + [{ "function": "urn:oasis:names:tc:xacml:1.0:function:string-equal", + "designator": { + "identifier": "urn:oasis:names:tc:xacml:1.0:action:action-id", + "category": "urn:oasis:names:tc:xacml:3.0:attribute-category:action", + "type": "http://www.w3.org/2001/XMLSchema#string", + "must_be_present": false + }, + "value": { + "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": "write" + }}]]], + "effect": "permit", + "obligations": [], + "advice": [] +} + +allow := evaluate_policyset_decision(IIA003_policy, [evaluate_rule_decision(IIA003_rule)]) diff --git a/benchmarks/rego/iia006.json b/benchmarks/rego/iia006.json new file mode 100644 index 0000000..51b1edc --- /dev/null +++ b/benchmarks/rego/iia006.json @@ -0,0 +1 @@ +{"request": [{"category":"urn:oasis:names:tc:xacml:1.0:subject-category:access-subject","identifier":"urn:oasis:names:tc:xacml:1.0:subject:subject-id","value":{"kind":"primitive","type":"http://www.w3.org/2001/XMLSchema#string","value":"Julius Hibbert"}},{"category":"urn:oasis:names:tc:xacml:1.0:subject-category:access-subject","identifier":"urn:oasis:names:tc:xacml:2.0:conformance-test:some-attribute","value":{"kind":"primitive","type":"http://www.w3.org/2001/XMLSchema#string","value":"riddle me this"}},{"category":"urn:oasis:names:tc:xacml:3.0:attribute-category:resource","identifier":"urn:oasis:names:tc:xacml:1.0:resource:resource-id","value":{"kind":"primitive","type":"http://www.w3.org/2001/XMLSchema#anyURI","value":"http://medico.com/record/patient/BartSimpson"}},{"category":"urn:oasis:names:tc:xacml:3.0:attribute-category:action","identifier":"urn:oasis:names:tc:xacml:1.0:action:action-id","value":{"kind":"primitive","type":"http://www.w3.org/2001/XMLSchema#string","value":"read"}}]} diff --git a/benchmarks/rego/iia006.rego b/benchmarks/rego/iia006.rego new file mode 100644 index 0000000..6a83b14 --- /dev/null +++ b/benchmarks/rego/iia006.rego @@ -0,0 +1,827 @@ +package equivalence + +import future.keywords.every +import future.keywords.if +import future.keywords.in + +######################################################################## +# Data Types +######################################################################## + +## MatchResult + +# - is_match => { "match_result": true } +# - no_match => { "match_result": false } +# - indeterminate => { "match_result": "indeterminate" } + +## Decision + +# - permit => { "decision": "permit" } +# - deny => { "decision": "deny" } +# - not_applicable => { "decision": "not_applicable" } +# - indeterminate => { "decision": "indeterminate" } + +## Extended Decision + +# - permit => { "decision_extended": "permit" } +# - deny => { "decision_extended": "deny" } +# - not_applicable => { "decision_extended": "not_applicable" } +# - indeterminate => { "decision_extended": "indeterminate" } +# - indeterminate_d => { "decision_extended": "indeterminate_d" } +# - indeterminate_p => { "decision_extended": "indeterminate_p" } +# - indeterminate_dp => { "decision_extended": "indeterminate_dp" } + +lift_decision_indeterminate({ "decision": "not_applicable" }) := { "decision": "not_applicable" } +lift_decision_indeterminate({ "decision": "permit" }) := { "decision": "indeterminate_p" } +lift_decision_indeterminate({ "decision": "deny" }) := { "decision": "indeterminate_d" } +lift_decision_indeterminate({ "decision": "indeterminate" }) := { "decision": "indeterminate_dp" } +lift_decision_indeterminate({ "decision": "indeterminate_dp" }) := { "decision": "indeterminate_dp" } +lift_decision_indeterminate({ "decision": "indeterminate_p" }) := { "decision": "indeterminate_p" } +lift_decision_indeterminate({ "decision": "indeterminate_d" }) := { "decision": "indeterminate_d" } + +## Value + +# - { "kind": "primitive", +# "type": string, +# "value": string } +# - { "kind": "bag", +# "values": ... } + +### Booleans + +true_value := { "kind": "primitive", "type": "boolean", "value": true } +false_value := { "kind": "primitive", "type": "boolean", "value": false } +indeterminate_value := { "kind": "primitive", "type": "boolean" } + +is_indeterminate(value) if { is_null(value.value) } + +## StatusCode + +# - ok => { "status": "ok" } +# - missing_attribute => { "status": "missing_attribute" } +# - syntax_error => { "status": "syntax_error" } +# - processing_error => { "status": "processing_error" } + +## AttributeDesignator + +# - { category : string +# identifier : string +# type : string +# issuer : string or null +# must_be_present : boolean } + +## Expression + +# - { "expression": "apply", +# "function": string, +# "args": [string, ...] } +# - { "expression": "attribute_designator", +# "inner": AttributeDesignator } +# - { "expression": "attribute_value", +# "inner": Value } +# - { "expression": "function" +# "function": string } + +## Match + +# - { "function": string, +# "designator": AttributeDesignator, +# "value": Value } + +## Obligation + +# - { "assignments": [Attribute, ...], +# "identifier": string } + +## ObligationExpression + +# - { "assignments": [AttributeAssignmentExpression, ...], +# "identifier": string, +# "fulfill_on": Decision } + +## Advice + +# - { "assignments": [Attribute, ...], +# "identifier": string } + +## AdviceExpression + +# - { "assignments": [AttributeAssignmentExpression, ...], +# "identifier": string, +# "applies_to": Decision } + +## AttributeAssignmentExpression + +# - { "category": string, +# "identifier": string, +# "issuer": string or null, +# "expression": Expression } + +## Target: [[[Expression, ...], ...], ...] + +## Rule + +# - { "target": Target, +# "condition": Expression or null, +# "effect": "permit" or "deny", +# "obligations": [ObligationExpression, ...], +# "advice": [AdviceExpression, ...] } + +## Policy + +# - { "combinator": string, +# "target": Target, +# "obligations": [ObligationExpression, ...], +# "advice": [AdviceExpression, ...] } + +## PolicySet + +# - { "combinator": string, +# "target": Target, +# "obligations": [ObligationExpression, ...], +# "advice": [AdviceExpression, ...] } + +# We assume the request attributes are stored in `input.request` as an array or set of +# +# { category : string +# identifier : string +# issuer : string or null +# value : [Value, ...] } + +######################################################################## +# Match Functions +######################################################################## + +apply_xacml_function( + "urn:oasis:names:tc:xacml:1.0:function:string-equal", + [{ "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": a }, + { "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": b }]) := true_value if { + a == b +} else := false_value +apply_xacml_function( + "urn:oasis:names:tc:xacml:1.0:function:anyURI-equal", + [{ "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#anyURI", + "value": a }, + { "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#anyURI", + "value": b }]) := true_value if { + a == b +} else := false_value + +######################################################################## +# AttributeDesignator +######################################################################## + +designator_matches(designator, attribute) if { + attribute.category == designator.category + attribute.identifier == designator.identifier + attribute.value.type == designator.type + not attribute.attr.issuer +} + +designator_matches(designator, attribute) if { + attribute.category == designator.category + attribute.identifier == designator.identifier + attribute.value.type == designator.type + attribute.attr.issuer == designator.issuer +} + +evaluate_designator(designator) := { "kind": "bag", "values": xs } if { + xs := [y.value | y := input.request[_]; designator_matches(designator, y)] + count(xs) > 1 +} + +evaluate_designator(designator) := xs[0] if { + xs := [y.value | y := input.request[_]; designator_matches(designator, y)] + count(xs) == 1 +} + +evaluate_designator(designator) := { "kind": "bag", "values": xs } if { + xs := [y.value | y := input.request[_]; designator_matches(designator, y)] + count(xs) == 0 + not designator.must_be_present +} + +evaluate_designator(designator) := { "status": "missing_attribute" } if { + xs := [y.value | y := input.request[_]; designator_matches(designator, y)] + count(xs) == 0 + designator.must_be_present +} + +######################################################################### +# Match +######################################################################## + +evaluate_match(match) := { "match_result": true_value } if { + designator_result := evaluate_designator(match.designator) + + # Designator evaluates without error. + designator_result + + some x in designator_result.values + apply_xacml_function(match.function, [x, match.value]).value == true +} else := { "match_result": true_value } if { + designator_result := evaluate_designator(match.designator) + + # Designator evaluates without error. + designator_result + + apply_xacml_function(match.function, [designator_result, match.value]).value == true +} else := { "match_result": indeterminate_value } if { + designator_result := evaluate_designator(match.designator) + + # Designator evaluates without error. + designator_result + + some x in designator_result + is_indeterminate(apply_xacml_function(match.function, [x, match.value])) +} else := { "match_result": false_value } if { + designator_result := evaluate_designator(match.designator) + + # Designator evaluates without error. + designator_result +} else := { "match_result": indeterminate_value } + +# Last case runs when evaluating the designator results in an error. + +evaluate_all_of(conj) := { "match_result": true_value } if { + every x in conj { + evaluate_match(x).match_result.value == true + } +} else := { "match_result": "indeterminate" } if { + some x in conj + is_indeterminate(evaluate_match(x).match_result) +} else := { "match_result": "no_match" } + +evaluate_any_of([]) := { "match_result": true_value } +evaluate_any_of(disj) := { "match_result": true_value } if { + some x in disj + evaluate_all_of(x) == { "match_result": true_value } +} else := { "match_result": "indeterminate" } if { + some x in disj + evaluate_all_of(x) == { "match_result": true_value } +} else := { "match_result": "no_match" } + + +######################################################################## +# Target +######################################################################## + +evaluate_target([]) := { "match_result": true_value } +evaluate_target(xs) := { "match_result": true_value } if { + every disj in xs { + evaluate_any_of(disj).match_result.value == true + } +} else := { "match_result": false_value } if { + some disj in xs + evaluate_any_of(disj).match_result.value == false +} else := { "match_result": indeterminate_value } + +######################################################################## +# Expression +######################################################################## + +evaluate_expression({ "expression": "apply", "function": function_name, "args": args }) := x if { + x := apply_xacml_function(function_name, args) +} +evaluate_expression({ "expression": "attribute_designator", "inner": designator }) := x if { + x := evaluate_designator(designator) +} +evaluate_expression({ "expression": "attribute_value", "inner": value }) := x if { + x := value +} +evaluate_expression({ "expression": "function", "function": name }) := x if { + x := name +} + +######################################################################## +# Obligations and Advice +######################################################################## + +evaluate_attribute_assignment_expression(expr) := assignment { + { "kind": "primitive", "value": inner } = evaluate_expression(expr.expression) + assignment := { "category": expr.category, + "identifier": expr.identifier, + "issuer": expr.issuer, + "value": inner } +} + +evaluate_obligation_expression(obligation_expression) := obligation { + assignments := [evaluate_attribute_assignment_expression(expr) | expr := obligation_expression.assignments[_]] + obligation := { "assignments": assignments, "identifier": obligation_expression.identifier } +} + +evaluate_advice_expression(advice_expression) := advice { + assignments := [evaluate_attribute_assignment_expression(expr) | expr := advice_expression.assignments[_]] + advice := { "assignments": assignments, "identifier": advice_expression.identifier } +} + + +######################################################################## +# Rule +######################################################################## + +# Condition is specified and applicable +evaluate_rule_decision(rule) := { "decision_extended": decision } { + evaluate_target(rule.target).match_result.value == true + + is_object(rule.condition) + evaluate_expression(rule.condition) == true + + decision := rule.effect +} +# Condition is specified and not applicable +evaluate_rule_decision(rule) := { "decision_extended": "not_applicable" } { + evaluate_target(rule.target).match_result.value == true + evaluate_expression(rule.condition) == false +} +# Condition is indeterminate +evaluate_rule_decision(rule) := { "decision_extended": "indeterminate_p" } { + evaluate_target(rule.target).match_result.value == true + condition := evaluate_expression(rule.condition) + is_null(condition) + rule.effect == "permit" +} +evaluate_rule_decision(rule) := { "decision_extended": "indeterminate_d" } { + evaluate_target(rule.target).match_result.value == true + condition := evaluate_expression(rule.condition) + is_null(condition) + rule.effect == "deny" +} +# Condition is unspecified +evaluate_rule_decision(rule) := { "decision_extended": decision } { + evaluate_target(rule.target).match_result.value == true + decision := rule.effect +} + +evaluate_rule_decision(rule) := { "decision_extended": "not_applicable" } { + evaluate_target(rule.target).match_result.value == false +} +evaluate_rule_decision(rule) := { "decision_extended": "indeterminate_p" } { + is_indeterminate(evaluate_target(rule.target)) + rule.effect == "permit" +} +evaluate_rule_decision(rule) := { "decision_extended": "indeterminate_d" } { + is_indeterminate(evaluate_target(rule.target)) + rule.effect == "permit" +} + +evaluate_rule_advices(rule) := { "advice": advice } if { + decision := evaluate_rule_decision(rule) + advice := [expr | expr := rule.advice[_]; expr.applies_to == decision ] +} + +evaluate_rule_obligations(rule) := { "obligations": obligations } if { + decision := evaluate_rule_decision(rule) + obligations := [expr | expr := rule.obligations[_]; expr.fulfill_on == decision ] +} + +######################################################################## +# Policy +######################################################################## + +evaluate_rule_combinator("deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("ordered_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("ordered_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("deny_unless_permit", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "deny" } + +evaluate_rule_combinator("permit_unless_deny", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "permit" } + +evaluate_rule_combinator("first_applicable", results) := result if { + indices := [i | results[i].decision_extended != "not_applicable"] + count(indices) > 0 + result := results[max(indices)] + result.decision_extended == "deny" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("legacy_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("ordered_legacy_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("legacy_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("ordered_legacy_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +# child_results := [result | rule := policy.rules[_]; result := evaluate_rule_decision(rule)] +evaluate_policy_decision(policy, child_results) := decision if { + evaluate_target(policy.target).match_result.value == true + decision := evaluate_rule_combinator(policy.combinator, child_results) +} else := decision if { + is_indeterminate(evaluate_target(policy.target)) + decision := lift_decision_indeterminate(evaluate_rule_combinator(policy.combinator, child_results)) +} else := { "decision_extended": "not_applicable" } + +# children_advice := [advice | rule := policy.rules[_]; expr := evaluate_rule_advices(rule); advice := expr[_]] +evaluate_policy_advices(policy, child_results, children_advice) := { "advice" : advice } if { + decision := evaluate_policy_decision(policy, child_results) + policy_advice := [expr | expr := policy.advice[_]; expr.applies_to == decision ] + advice := array.concat(policy_advice, children_advice) +} + +# children_obligations := [obligation | rule := policy.rules[_]; expr := evaluate_rule_obligations(rule); obligation := expr[_]] +evaluate_policy_obligations(policy, child_results, children_obligations) := { "obligations" : obligations } if { + decision := evaluate_policy_decision(policy, child_results) + policy_obligations := [expr | expr := policy.obligations[_]; expr.applies_to == decision ] + obligations := array.concat(policy_obligations, children_obligations) +} + +######################################################################## +# PolicySet +######################################################################## + +evaluate_policy_combinator("deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("ordered_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("ordered_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("deny_unless_permit", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "deny" } + +evaluate_policy_combinator("permit_unless_deny", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "permit" } + +evaluate_policy_combinator("first_applicable", results) := result if { + indices := [i | results[i].decision_extended != "not_applicable"] + count(indices) > 0 + result := results[max(indices)] + result.decision_extended == "deny" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("only_one_applicable", results) := result if { + applicable := [result | result := results[i]; result.decision_extended != "not_applicable"] + count(applicable) == 1 + result := applicable[0] +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("legacy_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "indeterminate" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("ordered_legacy_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "indeterminate" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("legacy_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("ordered_legacy_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_policyset_decision(policyset, child_results) := decision if { + evaluate_target(policyset.target).match_result.value == true + decision := evaluate_policy_combinator(policyset.combinator, child_results) +} else := decision if { + is_indeterminate(evaluate_target(policyset.target)) + decision := lift_decision_indeterminate(evaluate_policy_combinator(policyset.combinator, child_results)) +} else := { "decision_extended": "not_applicable" } + +evaluate_policyset_advices(policyset, child_results, child_advice) := { "advice" : advice } if { + decision := evaluate_policyset_decision(policyset, child_results) + policyset_advice := [expr | expr := policyset.advice[_]; expr.applies_to == decision ] + advice := array.concat(policyset_advice, child_advice) +} + +evaluate_policyset_obligations(policyset, child_results, child_obligations) := { "obligations" : obligations } if { + decision := evaluate_policyset_decision(policyset, child_results) + policyset_obligations := [expr | expr := policyset.obligations[_]; expr.applies_to == decision ] + obligations := array.concat(policyset_obligations, child_obligations) +} + +IIA006_policy := { + "combinator": "deny_overrides", + "target": [], + "obligations": [], + "advice": [] +} + +IIA006_rule := { + "target": [[[{ "function": "urn:oasis:names:tc:xacml:1.0:function:string-equal", + "designator": { + "identifier": "urn:oasis:names:tc:xacml:1.0:subject:subject-id", + "category": "urn:oasis:names:tc:xacml:1.0:subject-category:access-subject", + "type": "http://www.w3.org/2001/XMLSchema#string", + "must_be_present": false + }, + "value": { + "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": "Julius Hibbert" + }}, + { "function": "urn:oasis:names:tc:xacml:1.0:function:string-equal", + "designator": { + "identifier": "urn:oasis:names:tc:xacml:2.0:conformance-test:some-attribute", + "category": "urn:oasis:names:tc:xacml:1.0:subject-category:access-subject", + "type": "http://www.w3.org/2001/XMLSchema#string", + "must_be_present": false + }, + "value": { + "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": "riddle me this" + }}]], + [[{ "function": "urn:oasis:names:tc:xacml:1.0:function:anyURI-equal", + "designator": { + "identifier": "urn:oasis:names:tc:xacml:1.0:resource:resource-id", + "category": "urn:oasis:names:tc:xacml:3.0:attribute-category:resource", + "type": "http://www.w3.org/2001/XMLSchema#anyURI", + "must_be_present": false + }, + "value": { + "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#anyURI", + "value": "http://medico.com/record/patient/BartSimpson" + }}]], + [[{ "function": "urn:oasis:names:tc:xacml:1.0:function:string-equal", + "designator": { + "identifier": "urn:oasis:names:tc:xacml:1.0:action:action-id", + "category": "urn:oasis:names:tc:xacml:3.0:attribute-category:action", + "type": "http://www.w3.org/2001/XMLSchema#string", + "must_be_present": false + }, + "value": { + "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": "read" + }}], + [{ "function": "urn:oasis:names:tc:xacml:1.0:function:string-equal", + "designator": { + "identifier": "urn:oasis:names:tc:xacml:1.0:action:action-id", + "category": "urn:oasis:names:tc:xacml:3.0:attribute-category:action", + "type": "http://www.w3.org/2001/XMLSchema#string", + "must_be_present": false + }, + "value": { + "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": "write" + }}]]], + "effect": "permit", + "obligations": [], + "advice": [] +} + +allow := evaluate_policyset_decision(IIA006_policy, [evaluate_rule_decision(IIA006_rule)]) diff --git a/benchmarks/rego/iia007.rego b/benchmarks/rego/iia007.rego new file mode 100644 index 0000000..b4aa619 --- /dev/null +++ b/benchmarks/rego/iia007.rego @@ -0,0 +1,829 @@ +package equivalence + +import future.keywords.every +import future.keywords.if +import future.keywords.in + +######################################################################## +# Data Types +######################################################################## + +## MatchResult + +# - is_match => { "match_result": true } +# - no_match => { "match_result": false } +# - indeterminate => { "match_result": "indeterminate" } + +## Decision + +# - permit => { "decision": "permit" } +# - deny => { "decision": "deny" } +# - not_applicable => { "decision": "not_applicable" } +# - indeterminate => { "decision": "indeterminate" } + +## Extended Decision + +# - permit => { "decision_extended": "permit" } +# - deny => { "decision_extended": "deny" } +# - not_applicable => { "decision_extended": "not_applicable" } +# - indeterminate => { "decision_extended": "indeterminate" } +# - indeterminate_d => { "decision_extended": "indeterminate_d" } +# - indeterminate_p => { "decision_extended": "indeterminate_p" } +# - indeterminate_dp => { "decision_extended": "indeterminate_dp" } + +lift_decision_indeterminate({ "decision": "not_applicable" }) := { "decision": "not_applicable" } +lift_decision_indeterminate({ "decision": "permit" }) := { "decision": "indeterminate_p" } +lift_decision_indeterminate({ "decision": "deny" }) := { "decision": "indeterminate_d" } +lift_decision_indeterminate({ "decision": "indeterminate" }) := { "decision": "indeterminate_dp" } +lift_decision_indeterminate({ "decision": "indeterminate_dp" }) := { "decision": "indeterminate_dp" } +lift_decision_indeterminate({ "decision": "indeterminate_p" }) := { "decision": "indeterminate_p" } +lift_decision_indeterminate({ "decision": "indeterminate_d" }) := { "decision": "indeterminate_d" } + +## Value + +# - { "kind": "primitive", +# "type": string, +# "value": string } +# - { "kind": "bag", +# "values": ... } + +### Booleans + +true_value := { "kind": "primitive", "type": "boolean", "value": true } +false_value := { "kind": "primitive", "type": "boolean", "value": false } +indeterminate_value := { "kind": "primitive", "type": "boolean" } + +is_indeterminate(value) if { is_null(value.value) } + +## StatusCode + +# - ok => { "status": "ok" } +# - missing_attribute => { "status": "missing_attribute" } +# - syntax_error => { "status": "syntax_error" } +# - processing_error => { "status": "processing_error" } + +## AttributeDesignator + +# - { category : string +# identifier : string +# type : string +# issuer : string or null +# must_be_present : boolean } + +## Expression + +# - { "expression": "apply", +# "function": string, +# "args": [string, ...] } +# - { "expression": "attribute_designator", +# "inner": AttributeDesignator } +# - { "expression": "attribute_value", +# "inner": Value } +# - { "expression": "function" +# "function": string } + +## Match + +# - { "function": string, +# "designator": AttributeDesignator, +# "value": Value } + +## Obligation + +# - { "assignments": [Attribute, ...], +# "identifier": string } + +## ObligationExpression + +# - { "assignments": [AttributeAssignmentExpression, ...], +# "identifier": string, +# "fulfill_on": Decision } + +## Advice + +# - { "assignments": [Attribute, ...], +# "identifier": string } + +## AdviceExpression + +# - { "assignments": [AttributeAssignmentExpression, ...], +# "identifier": string, +# "applies_to": Decision } + +## AttributeAssignmentExpression + +# - { "category": string, +# "identifier": string, +# "issuer": string or null, +# "expression": Expression } + +## Target: [[[Expression, ...], ...], ...] + +## Rule + +# - { "target": Target, +# "condition": Expression or null, +# "effect": "permit" or "deny", +# "obligations": [ObligationExpression, ...], +# "advice": [AdviceExpression, ...] } + +## Policy + +# - { "combinator": string, +# "target": Target, +# "obligations": [ObligationExpression, ...], +# "advice": [AdviceExpression, ...] } + +## PolicySet + +# - { "combinator": string, +# "target": Target, +# "obligations": [ObligationExpression, ...], +# "advice": [AdviceExpression, ...] } + +# We assume the request attributes are stored in `input.request` as an array or set of +# +# { category : string +# identifier : string +# issuer : string or null +# value : [Value, ...] } + +######################################################################## +# Match Functions +######################################################################## + +apply_xacml_function( + "urn:oasis:names:tc:xacml:1.0:function:string-equal", + [{ "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": a }, + { "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": b }]) := true_value if { + a == b +} else := false_value +apply_xacml_function( + "urn:oasis:names:tc:xacml:1.0:function:anyURI-equal", + [{ "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#anyURI", + "value": a }, + { "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#anyURI", + "value": b }]) := true_value if { + a == b +} else := false_value + +######################################################################## +# AttributeDesignator +######################################################################## + +designator_matches(designator, attribute) if { + attribute.category == designator.category + attribute.identifier == designator.identifier + attribute.value.type == designator.type + not attribute.attr.issuer +} + +designator_matches(designator, attribute) if { + attribute.category == designator.category + attribute.identifier == designator.identifier + attribute.value.type == designator.type + attribute.attr.issuer == designator.issuer +} + +evaluate_designator(designator) := { "kind": "bag", "values": xs } if { + xs := [y.value | y := input.request[_]; designator_matches(designator, y)] + count(xs) > 1 +} + +evaluate_designator(designator) := xs[0] if { + xs := [y.value | y := input.request[_]; designator_matches(designator, y)] + count(xs) == 1 +} + +evaluate_designator(designator) := { "kind": "bag", "values": xs } if { + xs := [y.value | y := input.request[_]; designator_matches(designator, y)] + count(xs) == 0 + not designator.must_be_present +} + +evaluate_designator(designator) := { "status": "missing_attribute" } if { + xs := [y.value | y := input.request[_]; designator_matches(designator, y)] + count(xs) == 0 + designator.must_be_present +} + +######################################################################### +# Match +######################################################################## + +evaluate_match(match) := { "match_result": true_value } if { + designator_result := evaluate_designator(match.designator) + + # Designator evaluates without error. + designator_result + + some x in designator_result.values + apply_xacml_function(match.function, [x, match.value]).value == true +} else := { "match_result": true_value } if { + designator_result := evaluate_designator(match.designator) + + # Designator evaluates without error. + designator_result + + apply_xacml_function(match.function, [designator_result, match.value]).value == true +} else := { "match_result": indeterminate_value } if { + designator_result := evaluate_designator(match.designator) + + # Designator evaluates without error. + designator_result + + some x in designator_result + is_indeterminate(apply_xacml_function(match.function, [x, match.value])) +} else := { "match_result": false_value } if { + designator_result := evaluate_designator(match.designator) + + # Designator evaluates without error. + designator_result +} else := { "match_result": indeterminate_value, "status": designator_result.status } if { + designator_result := evaluate_designator(match.designator) +} + +# Last case runs when evaluating the designator results in an error. + +evaluate_all_of(conj) := { "match_result": true_value } if { + every x in conj { + evaluate_match(x).match_result.value == true + } +} else := { "match_result": "indeterminate", "status": x.status } if { + some x in conj + is_indeterminate(evaluate_match(x).match_result) +} else := { "match_result": "no_match" } + +evaluate_any_of([]) := { "match_result": true_value } +evaluate_any_of(disj) := { "match_result": true_value } if { + some x in disj + evaluate_all_of(x) == { "match_result": true_value } +} else := { "match_result": "indeterminate", "status": x.status } if { + some x in disj + is_indeterminate(evaluate_all_of(x)) +} else := { "match_result": "no_match" } + + +######################################################################## +# Target +######################################################################## + +evaluate_target([]) := { "match_result": true_value } +evaluate_target(xs) := { "match_result": true_value } if { + every disj in xs { + evaluate_any_of(disj).match_result.value == true + } +} else := { "match_result": false_value } if { + some disj in xs + evaluate_any_of(disj).match_result == "no_match" +} else := { "match_result": indeterminate_value } + +######################################################################## +# Expression +######################################################################## + +evaluate_expression({ "expression": "apply", "function": function_name, "args": args }) := x if { + x := apply_xacml_function(function_name, args) +} +evaluate_expression({ "expression": "attribute_designator", "inner": designator }) := x if { + x := evaluate_designator(designator) +} +evaluate_expression({ "expression": "attribute_value", "inner": value }) := x if { + x := value +} +evaluate_expression({ "expression": "function", "function": name }) := x if { + x := name +} + +######################################################################## +# Obligations and Advice +######################################################################## + +evaluate_attribute_assignment_expression(expr) := assignment { + { "kind": "primitive", "value": inner } = evaluate_expression(expr.expression) + assignment := { "category": expr.category, + "identifier": expr.identifier, + "issuer": expr.issuer, + "value": inner } +} + +evaluate_obligation_expression(obligation_expression) := obligation { + assignments := [evaluate_attribute_assignment_expression(expr) | expr := obligation_expression.assignments[_]] + obligation := { "assignments": assignments, "identifier": obligation_expression.identifier } +} + +evaluate_advice_expression(advice_expression) := advice { + assignments := [evaluate_attribute_assignment_expression(expr) | expr := advice_expression.assignments[_]] + advice := { "assignments": assignments, "identifier": advice_expression.identifier } +} + + +######################################################################## +# Rule +######################################################################## + +# Condition is specified and applicable +evaluate_rule_decision(rule) := { "decision_extended": decision } { + evaluate_target(rule.target).match_result.value == true + + is_object(rule.condition) + evaluate_expression(rule.condition) == true + + decision := rule.effect +} +# Condition is specified and not applicable +evaluate_rule_decision(rule) := { "decision_extended": "not_applicable" } { + evaluate_target(rule.target).match_result.value == true + evaluate_expression(rule.condition) == false +} +# Condition is indeterminate +evaluate_rule_decision(rule) := { "decision_extended": "indeterminate_p" } { + evaluate_target(rule.target).match_result.value == true + condition := evaluate_expression(rule.condition) + is_null(condition) + rule.effect == "permit" +} +evaluate_rule_decision(rule) := { "decision_extended": "indeterminate_d" } { + evaluate_target(rule.target).match_result.value == true + condition := evaluate_expression(rule.condition) + is_null(condition) + rule.effect == "deny" +} +# Condition is unspecified +evaluate_rule_decision(rule) := { "decision_extended": decision } { + evaluate_target(rule.target).match_result.value == true + decision := rule.effect +} + +evaluate_rule_decision(rule) := { "decision_extended": "not_applicable" } { + evaluate_target(rule.target).match_result.value == false +} +evaluate_rule_decision(rule) := { "decision_extended": "indeterminate_p" } { + is_indeterminate(evaluate_target(rule.target)) + rule.effect == "permit" +} +evaluate_rule_decision(rule) := { "decision_extended": "indeterminate_d" } { + is_indeterminate(evaluate_target(rule.target)) + rule.effect == "permit" +} + +evaluate_rule_advices(rule) := { "advice": advice } if { + decision := evaluate_rule_decision(rule) + advice := [expr | expr := rule.advice[_]; expr.applies_to == decision ] +} + +evaluate_rule_obligations(rule) := { "obligations": obligations } if { + decision := evaluate_rule_decision(rule) + obligations := [expr | expr := rule.obligations[_]; expr.fulfill_on == decision ] +} + +######################################################################## +# Policy +######################################################################## + +evaluate_rule_combinator("deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("ordered_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("ordered_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("deny_unless_permit", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "deny" } + +evaluate_rule_combinator("permit_unless_deny", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "permit" } + +evaluate_rule_combinator("first_applicable", results) := result if { + indices := [i | results[i].decision_extended != "not_applicable"] + count(indices) > 0 + result := results[max(indices)] + result.decision_extended == "deny" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("legacy_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("ordered_legacy_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("legacy_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_rule_combinator("ordered_legacy_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +# child_results := [result | rule := policy.rules[_]; result := evaluate_rule_decision(rule)] +evaluate_policy_decision(policy, child_results) := decision if { + evaluate_target(policy.target).match_result.value == true + decision := evaluate_rule_combinator(policy.combinator, child_results) +} else := decision if { + is_indeterminate(evaluate_target(policy.target)) + decision := lift_decision_indeterminate(evaluate_rule_combinator(policy.combinator, child_results)) +} else := { "decision_extended": "not_applicable" } + +# children_advice := [advice | rule := policy.rules[_]; expr := evaluate_rule_advices(rule); advice := expr[_]] +evaluate_policy_advices(policy, child_results, children_advice) := { "advice" : advice } if { + decision := evaluate_policy_decision(policy, child_results) + policy_advice := [expr | expr := policy.advice[_]; expr.applies_to == decision ] + advice := array.concat(policy_advice, children_advice) +} + +# children_obligations := [obligation | rule := policy.rules[_]; expr := evaluate_rule_obligations(rule); obligation := expr[_]] +evaluate_policy_obligations(policy, child_results, children_obligations) := { "obligations" : obligations } if { + decision := evaluate_policy_decision(policy, child_results) + policy_obligations := [expr | expr := policy.obligations[_]; expr.applies_to == decision ] + obligations := array.concat(policy_obligations, children_obligations) +} + +######################################################################## +# PolicySet +######################################################################## + +evaluate_policy_combinator("deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("ordered_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("ordered_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate_dp" } if { + some result in results + result.decision_extended == "indeterminate_dp" +} else := { "decision_extended": "indeterminate_dp" } if { + some result1 in results + some result2 in results + result1.decision_extended == "indeterminate_d" + result1.decision_extended == "indeterminate_p" +} else := { "decision_extended": "indeterminate_p" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate_d" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("deny_unless_permit", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "deny" } + +evaluate_policy_combinator("permit_unless_deny", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "permit" } + +evaluate_policy_combinator("first_applicable", results) := result if { + indices := [i | results[i].decision_extended != "not_applicable"] + count(indices) > 0 + result := results[max(indices)] + result.decision_extended == "deny" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("only_one_applicable", results) := result if { + applicable := [result | result := results[i]; result.decision_extended != "not_applicable"] + count(applicable) == 1 + result := applicable[0] +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("legacy_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "indeterminate" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("ordered_legacy_deny_overrides", results) := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "indeterminate" +} else := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("legacy_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate" +} else := { "decision_extended": "not_applicable" } + +evaluate_policy_combinator("ordered_legacy_permit_overrides", results) := { "decision_extended": "permit" } if { + some result in results + result.decision_extended == "permit" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_p" +} else := { "decision_extended": "deny" } if { + some result in results + result.decision_extended == "deny" +} else := { "decision_extended": "indeterminate" } if { + some result in results + result.decision_extended == "indeterminate_d" +} else := { "decision_extended": "not_applicable" } + +evaluate_policyset_decision(policyset, child_results) := decision if { + evaluate_target(policyset.target).match_result.value == true + decision := evaluate_policy_combinator(policyset.combinator, child_results) +} else := decision if { + is_indeterminate(evaluate_target(policyset.target)) + decision := lift_decision_indeterminate(evaluate_policy_combinator(policyset.combinator, child_results)) +} else := { "decision_extended": "not_applicable" } + +evaluate_policyset_advices(policyset, child_results, child_advice) := { "advice" : advice } if { + decision := evaluate_policyset_decision(policyset, child_results) + policyset_advice := [expr | expr := policyset.advice[_]; expr.applies_to == decision ] + advice := array.concat(policyset_advice, child_advice) +} + +evaluate_policyset_obligations(policyset, child_results, child_obligations) := { "obligations" : obligations } if { + decision := evaluate_policyset_decision(policyset, child_results) + policyset_obligations := [expr | expr := policyset.obligations[_]; expr.applies_to == decision ] + obligations := array.concat(policyset_obligations, child_obligations) +} + +IIA007_policy := { + "combinator": "deny_overrides", + "target": [], + "obligations": [], + "advice": [] +} + +IIA007_rule := { + "target": [[[{ "function": "urn:oasis:names:tc:xacml:1.0:function:string-equal", + "designator": { + "identifier": "urn:oasis:names:tc:xacml:1.0:subject:subject-id", + "category": "urn:oasis:names:tc:xacml:1.0:subject-category:access-subject", + "type": "http://www.w3.org/2001/XMLSchema#string", + "must_be_present": true + }, + "value": { + "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": "Julius Hibbert" + }}, + { "function": "urn:oasis:names:tc:xacml:1.0:function:string-equal", + "designator": { + "identifier": "urn:oasis:names:tc:xacml:2.0:conformance-test:some-attribute", + "category": "urn:oasis:names:tc:xacml:1.0:subject-category:access-subject", + "type": "http://www.w3.org/2001/XMLSchema#string", + "must_be_present": true + }, + "value": { + "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": "riddle me this" + }}]], + [[{ "function": "urn:oasis:names:tc:xacml:1.0:function:anyURI-equal", + "designator": { + "identifier": "urn:oasis:names:tc:xacml:1.0:resource:resource-id", + "category": "urn:oasis:names:tc:xacml:3.0:attribute-category:resource", + "type": "http://www.w3.org/2001/XMLSchema#anyURI", + "must_be_present": false + }, + "value": { + "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#anyURI", + "value": "http://medico.com/record/patient/BartSimpson" + }}]], + [[{ "function": "urn:oasis:names:tc:xacml:1.0:function:string-equal", + "designator": { + "identifier": "urn:oasis:names:tc:xacml:1.0:action:action-id", + "category": "urn:oasis:names:tc:xacml:3.0:attribute-category:action", + "type": "http://www.w3.org/2001/XMLSchema#string", + "must_be_present": false + }, + "value": { + "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": "read" + }}], + [{ "function": "urn:oasis:names:tc:xacml:1.0:function:string-equal", + "designator": { + "identifier": "urn:oasis:names:tc:xacml:1.0:action:action-id", + "category": "urn:oasis:names:tc:xacml:3.0:attribute-category:action", + "type": "http://www.w3.org/2001/XMLSchema#string", + "must_be_present": false + }, + "value": { + "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": "write" + }}]]], + "effect": "permit", + "obligations": [], + "advice": [] +} + +allow := evaluate_policyset_decision(IIA007_policy, [evaluate_rule_decision(IIA007_rule)]) diff --git a/benchmarks/rego/iia1.json b/benchmarks/rego/iia1.json new file mode 100644 index 0000000..660d7c1 --- /dev/null +++ b/benchmarks/rego/iia1.json @@ -0,0 +1 @@ +{"request": [{"category":"urn:oasis:names:tc:xacml:1.0:subject-category:access-subject","identifier":"urn:oasis:names:tc:xacml:1.0:subject:subject-id","value":{"kind":"primitive","type":"http://www.w3.org/2001/XMLSchema#string","value":"Julius Hibbert"}},{"category":"urn:oasis:names:tc:xacml:3.0:attribute-category:resource","identifier":"urn:oasis:names:tc:xacml:1.0:resource:resource-id","value":{"kind":"primitive","type":"http://www.w3.org/2001/XMLSchema#anyURI","value":"http://medico.com/record/patient/BartSimpson"}},{"category":"urn:oasis:names:tc:xacml:3.0:attribute-category:action","identifier":"urn:oasis:names:tc:xacml:1.0:action:action-id","value":{"kind":"primitive","type":"http://www.w3.org/2001/XMLSchema#string","value":"read"}}]} diff --git a/xacml-translation/match.rego b/benchmarks/rego/iia1.rego index df924bd..f7c2a04 100644 --- a/xacml-translation/match.rego +++ b/benchmarks/rego/iia1.rego @@ -152,8 +152,26 @@ is_indeterminate(value) if { is_null(value.value) } # Match Functions ######################################################################## -## TODO -apply_xacml_function("a", _) := true_value +apply_xacml_function( + "urn:oasis:names:tc:xacml:1.0:function:string-equal", + [{ "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": a }, + { "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": b }]) := true_value if { + a == b +} else := false_value +apply_xacml_function( + "urn:oasis:names:tc:xacml:1.0:function:anyURI-equal", + [{ "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#anyURI", + "value": a }, + { "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#anyURI", + "value": b }]) := true_value if { + a == b +} else := false_value ######################################################################## # AttributeDesignator @@ -163,7 +181,7 @@ designator_matches(designator, attribute) if { attribute.category == designator.category attribute.identifier == designator.identifier attribute.value.type == designator.type - attribute.attr.issuer == null + not attribute.attr.issuer } designator_matches(designator, attribute) if { @@ -173,17 +191,20 @@ designator_matches(designator, attribute) if { attribute.attr.issuer == designator.issuer } -evaluate_designator(designator) := result if { +evaluate_designator(designator) := { "kind": "bag", "values": xs } if { xs := [y.value | y := input.request[_]; designator_matches(designator, y)] - count(xs) > 0 - result := { "kind": "bag", "values": xs } + count(xs) > 1 } -evaluate_designator(designator) := result if { +evaluate_designator(designator) := xs[0] if { + xs := [y.value | y := input.request[_]; designator_matches(designator, y)] + count(xs) == 1 +} + +evaluate_designator(designator) := { "kind": "bag", "values": xs } if { xs := [y.value | y := input.request[_]; designator_matches(designator, y)] count(xs) == 0 not designator.must_be_present - result := { "kind": "bag", "values": xs } } evaluate_designator(designator) := { "status": "missing_attribute" } if { @@ -200,30 +221,37 @@ evaluate_match(match) := { "match_result": true_value } if { designator_result := evaluate_designator(match.designator) # Designator evaluates without error. - is_array(designator_result) + designator_result - some x in designator_result - apply_xacml_function(match.fn, x).value == true + some x in designator_result.values + apply_xacml_function(match.function, [x, match.value]).value == true +} else := { "match_result": true_value } if { + designator_result := evaluate_designator(match.designator) + + # Designator evaluates without error. + designator_result + + apply_xacml_function(match.function, [designator_result, match.value]).value == true } else := { "match_result": indeterminate_value } if { designator_result := evaluate_designator(match.designator) # Designator evaluates without error. - is_array(designator_result) + designator_result some x in designator_result - is_indeterminate(apply_xacml_function(match.fn, x)) + is_indeterminate(apply_xacml_function(match.function, [x, match.value])) } else := { "match_result": false_value } if { designator_result := evaluate_designator(match.designator) # Designator evaluates without error. - is_array(designator_result) + designator_result } else := { "match_result": indeterminate_value } # Last case runs when evaluating the designator results in an error. evaluate_all_of(conj) := { "match_result": true_value } if { every x in conj { - evaluate_match(x) == true + evaluate_match(x).match_result.value == true } } else := { "match_result": "indeterminate" } if { some x in conj @@ -722,3 +750,66 @@ evaluate_policyset_obligations(policyset, child_results, child_obligations) := { policyset_obligations := [expr | expr := policyset.obligations[_]; expr.applies_to == decision ] obligations := array.concat(policyset_obligations, child_obligations) } + +IIA1_policy := { + "combinator": "deny_overrides", + "target": [], + "obligations": [], + "advice": [] +} + +IIA1_rule := { + "target": [[[{ "function": "urn:oasis:names:tc:xacml:1.0:function:string-equal", + "designator": { + "identifier": "urn:oasis:names:tc:xacml:1.0:subject:subject-id", + "category": "urn:oasis:names:tc:xacml:1.0:subject-category:access-subject", + "type": "http://www.w3.org/2001/XMLSchema#string", + "must_be_present": false + }, + "value": { + "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": "Julius Hibbert" + }}]], + [[{ "function": "urn:oasis:names:tc:xacml:1.0:function:anyURI-equal", + "designator": { + "identifier": "urn:oasis:names:tc:xacml:1.0:resource:resource-id", + "category": "urn:oasis:names:tc:xacml:3.0:attribute-category:resource", + "type": "http://www.w3.org/2001/XMLSchema#anyURI", + "must_be_present": false + }, + "value": { + "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#anyURI", + "value": "http://medico.com/record/patient/BartSimpson" + }}]], + [[{ "function": "urn:oasis:names:tc:xacml:1.0:function:string-equal", + "designator": { + "identifier": "urn:oasis:names:tc:xacml:1.0:action:action-id", + "category": "urn:oasis:names:tc:xacml:3.0:attribute-category:action", + "type": "http://www.w3.org/2001/XMLSchema#string", + "must_be_present": false + }, + "value": { + "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": "read" + }}], + [{ "function": "urn:oasis:names:tc:xacml:1.0:function:string-equal", + "designator": { + "identifier": "urn:oasis:names:tc:xacml:1.0:action:action-id", + "category": "urn:oasis:names:tc:xacml:3.0:attribute-category:action", + "type": "http://www.w3.org/2001/XMLSchema#string", + "must_be_present": false + }, + "value": { + "kind": "primitive", + "type": "http://www.w3.org/2001/XMLSchema#string", + "value": "write" + }}]]], + "effect": "permit", + "obligations": [], + "advice": [] +} + +allow := evaluate_policyset_decision(IIA1_policy, [evaluate_rule_decision(IIA1_rule)]) diff --git a/rego-proofs/.gitignore b/rego-proofs/.gitignore new file mode 100644 index 0000000..73368ec --- /dev/null +++ b/rego-proofs/.gitignore @@ -0,0 +1,3 @@ +.lake/ +_build/ +*.olean diff --git a/rego-proofs/Rego/Rego.lean b/rego-proofs/Rego/Rego.lean index ce52b89..717a62c 100644 --- a/rego-proofs/Rego/Rego.lean +++ b/rego-proofs/Rego/Rego.lean @@ -1,5 +1,8 @@ +import Aesop import Lean.Data.AssocList import Lean.Data.Json +import Mathlib.Init.Logic +import Mathlib.Tactic.LibrarySearch namespace Rego @@ -7,64 +10,603 @@ inductive Any where -- Scalar types | null | bool (b : Bool) - | num (n : Lean.JsonNumber) + | num (n : Nat) | str (s : String) -- Composite types | array (xs : Array Any) | set (elts : List Any) -- FIXME: `List` obviously isn't correct here. - | object (field : Lean.AssocList String Any) + | object (field : Lean.AssocList Any Any) deriving Inhabited namespace Any -def expectBool (x : Any) : Option Bool := - if let Any.bool b := x then some b else none - -def expectNumber (x : Any) : Option Lean.JsonNumber := - if let Any.num n := x then some n else none - -def expectArray (x : Any) : Option (Array Any) := - if let Any.array y := x then some y else none - -def expectObject (x : Any) : Option (Lean.AssocList String Any) := - if let Any.object y := x then some y else none - -end Any - --- TODO: Complete implementation def eqv : Any → Any → Bool | Any.null, Any.null => True | Any.bool b₁, Any.bool b₂ => b₁ = b₂ + | Any.str s₁, Any.str s₂ => s₁ = s₂ + -- TODO: array, set, object | _, _ => False instance : BEq Any where beq := eqv -abbrev Set := List -abbrev Number := Lean.JsonNumber -abbrev Object := Lean.AssocList String Any +def deref (target : Any) (field : Any) : Any := + match target with + | array xs => + (match field with + | num x => xs.getD x Any.null + | _ => Any.null) + | set xs => + (match field with + | num x => xs.getD x Any.null + | _ => Any.null) + | object fields => + (match field with + | str s => Option.getD (fields.find? (str s)) Any.null + -- TODO: Coe to str + | _ => Any.null + ) + | _ => Any.null -namespace Number -def toNat' (n : Number) : Option Nat := - if n.exponent = 0 && n.mantissa ≥ 0 then - some (Int.toNat n.mantissa) - else none +end Any -end Number +def scalar_specified_by (x : Any) (ind : Any → Prop) : Prop := ind x -namespace Object +def set_specified_by (x : Any) (ind : Any → Prop) : Prop := + match x with + | Any.set xs => ∀ (k : Rego.Any), k ∈ xs ↔ ind k + | _ => False -def ref (obj : Object) (attr : String) : Option Any := - Lean.AssocList.find? attr obj +def object_specified_by (x : Any) (ind : Any → Prop) : Prop := + match x with + | Any.object xs => ∀ (k v : Rego.Any), (xs.find? k = some v) ↔ ind k + | _ => False -end Object +end Rego -def obj_eqv (x y : Object) : Bool := - (List.map Prod.snd (Lean.AssocList.toList x)) - == (List.map Prod.snd (Lean.AssocList.toList y)) +def eq (a b : Rego.Any) := if a == b then Rego.Any.bool true else Rego.Any.bool false +def equal (a b : Rego.Any) := if a == b then Rego.Any.bool true else Rego.Any.bool false -instance : BEq Object where - beq := obj_eqv +inductive XmlType + | string : XmlType + | boolean : XmlType + | integer : XmlType + | double : XmlType + | time : XmlType + | date : XmlType + | dateTime : XmlType + | anyURI : XmlType + | hexBinary : XmlType + | base64Binary : XmlType + | dayTimeDuration : XmlType + | yearMonthDuration : XmlType + | x500Name : XmlType + | rfc822Name : XmlType + | ipAddress : XmlType + | dnsName : XmlType +deriving BEq, Repr -end Rego +instance : LawfulBEq XmlType where + eq_of_beq {a b} h := by cases a <;> cases b <;> first | rfl | contradiction + rfl {a} := by cases a <;> decide + +structure AttributeDesignator where + category : String + identifier : String + type : XmlType + issuer : Option String + must_be_present : Bool +deriving BEq, Repr + +def Primitive : Type := XmlType × String +deriving BEq, Repr + +def Primitive.mk (type : XmlType) (inner : String) : Primitive := (type, inner) + +structure Bag where + contents: List Primitive +deriving Repr + +def Bag.beq (b₁ b₂ : Bag) : Bool := + b₁.contents.all (fun x => b₂.contents.count x == b₁.contents.count x) + +instance : BEq Bag where + beq := Bag.beq + +inductive Value where + | primitive (p : Primitive) : Value + | bag (b : Bag) : Value +deriving BEq, Repr + +structure Attribute where + category : String + identifier : String + issuer : Option String + value : Primitive +deriving Repr + +inductive StatusCode + | ok : StatusCode + | missing_attribute : StatusCode + | syntax_error : StatusCode + | processing_error : StatusCode +deriving BEq, Repr + +namespace AttributeDesignator + def eval (designator : AttributeDesignator) (context : List Attribute) : Sum Value (List StatusCode) := + match designator with + | AttributeDesignator.mk category identifier type issuer must_be_present => + let found := + -- A named attribute SHALL match an attribute if the values of + -- their respective Category, AttributeId, DataType and Issuer + -- attributes match. The attribute designator’s Category MUST + -- match, by identifier equality, the Category of the + -- <Attributes> element in which the attribute is present. The + -- attribute designator’s AttributeId MUST match, by identifier + -- equality, the AttributeId of the attribute. The attribute + -- designator’s DataType MUST match, by identifier equality, the + -- DataType of the same attribute. + -- + -- If the Issuer attribute is present in the attribute + -- designator, then it MUST match, using the + -- “urn:oasis:names:tc:xacml:1.0:function:string-equal” + -- function, the Issuer of the same attribute. If the Issuer is + -- not present in the attribute designator, then the matching of + -- the attribute to the named attribute SHALL be governed by + -- AttributeId and DataType attributes alone. + context.filter (fun (attr : Attribute) => + attr.category == category + ∧ attr.identifier == identifier + ∧ attr.value.fst == type + ∧ (attr.issuer == Option.none ∨ attr.issuer == issuer)) + let found := found.map (fun x => x.value) + if must_be_present then + match found with + | [] => Sum.inr $ [StatusCode.missing_attribute] + | _ => Sum.inl $ Value.bag (Bag.mk found) + else Sum.inl $ Value.bag (Bag.mk found) +end AttributeDesignator + +def attribute_matches (designator : AttributeDesignator) (attr : Attribute) : Prop := + match designator with + | AttributeDesignator.mk category identifier type issuer _ => + attr.category == category + ∧ attr.identifier == identifier + ∧ attr.value.fst == type + ∧ (attr.issuer == Option.none ∨ attr.issuer == issuer) + +def string_of_xmltype : XmlType → String + | XmlType.string => "string" + | XmlType.boolean => "boolean" + | XmlType.integer => "integer" + | XmlType.double => "double" + | XmlType.time => "time" + | XmlType.date => "date" + | XmlType.dateTime => "dateTime" + | XmlType.anyURI => "anyURI" + | XmlType.hexBinary => "hexBinary" + | XmlType.base64Binary => "base64Binary" + | XmlType.dayTimeDuration => "dayTimeDuration" + | XmlType.yearMonthDuration => "yearMonthDuration" + | XmlType.x500Name => "x500Name" + | XmlType.rfc822Name => "rfc822Name" + | XmlType.ipAddress => "ipAddress" + | XmlType.dnsName => "dnsName" + +@[simp] def toAssocList : List (α × β) → Lean.AssocList α β + | [] => Lean.AssocList.nil + | (a,b) :: es => Lean.AssocList.cons a b (toAssocList es) + +def rego_of_primitive : Primitive → Rego.Any + | (type, value) => + Rego.Any.object + (toAssocList + [(Rego.Any.str "kind" , Rego.Any.str "primitive"), + (Rego.Any.str "type" , Rego.Any.str (string_of_xmltype type)), + (Rego.Any.str "value" , Rego.Any.str value)]) + +def rego_of_attribute_designator : AttributeDesignator → Rego.Any + | AttributeDesignator.mk category identifier type (some issuer) must_be_present => + Rego.Any.object + (toAssocList + [(Rego.Any.str "category" , Rego.Any.str category), + (Rego.Any.str "identifier" , Rego.Any.str identifier), + (Rego.Any.str "type" , Rego.Any.str (string_of_xmltype type)), + (Rego.Any.str "issuer" , Rego.Any.str issuer), + (Rego.Any.str "must_be_present" , Rego.Any.bool must_be_present)]) + | AttributeDesignator.mk category identifier type (none) must_be_present => + Rego.Any.object + (toAssocList + [(Rego.Any.str "category" , Rego.Any.str category), + (Rego.Any.str "identifier" , Rego.Any.str identifier), + (Rego.Any.str "type" , Rego.Any.str (string_of_xmltype type)), + (Rego.Any.str "must_be_present" , Rego.Any.bool must_be_present)]) + +def rego_of_attribute : Attribute → Rego.Any + | Attribute.mk category identifier (some issuer) value => + Rego.Any.object + (toAssocList + [(Rego.Any.str "category" , Rego.Any.str category), + (Rego.Any.str "identifier" , Rego.Any.str identifier), + (Rego.Any.str "issuer" , Rego.Any.str issuer), + (Rego.Any.str "value" , (rego_of_primitive value))]) + | Attribute.mk category identifier _ value => + Rego.Any.object + (toAssocList + [(Rego.Any.str "category" , Rego.Any.str category), + (Rego.Any.str "identifier" , Rego.Any.str identifier), + (Rego.Any.str "value" , (rego_of_primitive value))]) + +inductive designator_matches (varg__1 varg__2 vy__0 : Rego.Any) : Prop where + | rule0 : (And (Ne (eq vy__0 (Rego.Any.bool True)) (Rego.Any.bool False)) + (And (Ne (equal (Rego.Any.deref varg__2 (Rego.Any.str "issuer")) (Rego.Any.null )) (Rego.Any.bool False)) + (And (Ne (equal (Rego.Any.deref (Rego.Any.deref varg__2 (Rego.Any.str "value")) (Rego.Any.str "type")) (Rego.Any.deref varg__1 (Rego.Any.str "type"))) (Rego.Any.bool False)) + (And (Ne (equal (Rego.Any.deref varg__2 (Rego.Any.str "identifier")) (Rego.Any.deref varg__1 (Rego.Any.str "identifier"))) (Rego.Any.bool False)) + (Ne (equal (Rego.Any.deref varg__2 (Rego.Any.str "category")) (Rego.Any.deref varg__1 (Rego.Any.str "category"))) (Rego.Any.bool False)))))) + → designator_matches varg__1 varg__2 vy__0 + | rule1 : (And (Ne (eq vy__0 (Rego.Any.bool True)) (Rego.Any.bool False)) + (And (Ne (equal (Rego.Any.deref varg__2 (Rego.Any.str "issuer")) (Rego.Any.deref varg__1 (Rego.Any.str "issuer"))) (Rego.Any.bool False)) + (And (Ne (equal (Rego.Any.deref (Rego.Any.deref varg__2 (Rego.Any.str "value")) (Rego.Any.str "type")) (Rego.Any.deref varg__1 (Rego.Any.str "type"))) (Rego.Any.bool False)) + (And (Ne (equal (Rego.Any.deref varg__2 (Rego.Any.str "identifier")) (Rego.Any.deref varg__1 (Rego.Any.str "identifier"))) (Rego.Any.bool False)) + (Ne (equal (Rego.Any.deref varg__2 (Rego.Any.str "category")) (Rego.Any.deref varg__1 (Rego.Any.str "category"))) (Rego.Any.bool False)))))) + → designator_matches varg__1 varg__2 vy__0 + +theorem category_inv' : + ∀ (attr : Attribute), + Rego.Any.deref (rego_of_attribute attr) (Rego.Any.str "category") = Rego.Any.str attr.category := by + unfold Rego.Any.deref + unfold rego_of_attribute + aesop + +@[simp] +theorem rego_str_eq : (Rego.Any.str s₁ == Rego.Any.str s₂) = (s₁ == s₂) := by + simp [BEq.beq, Rego.Any.instBEqAny, Rego.Any.eqv] + +@[simp] theorem const_str_neq₀ : ("category" == "identifier") = false := by rfl +@[simp] theorem const_str_neq₁ : ("category" == "value") = false := by rfl +@[simp] theorem const_str_neq₂ : ("identifier" == "value") = false := by rfl +@[simp] theorem const_str_neq₃ : ("issuer" == "value") = false := by rfl +@[simp] theorem const_str_neq₄ : ("category" == "type") = false := by rfl +@[simp] theorem const_str_neq₅ : ("identifier" == "type") = false := by rfl +@[simp] theorem const_str_neq₆ : ("kind" == "type") = false := by rfl +@[simp] theorem const_str_neq₇ : ("category" == "issuer") = false := by rfl +@[simp] theorem const_str_neq₈ : ("identifier" == "issuer") = false := by rfl +@[simp] theorem const_str_neq₉ : ("value" == "issuer") = false := by rfl +@[simp] theorem const_str_neq₁₀ : ("type" == "issuer") = false := by rfl +@[simp] theorem const_str_neq₁₁ : ("must_be_present" == "issuer") = false := by rfl + +@[simp] +theorem bool_comparison (cmp : Bool) : + ¬ (if cmp = true then Rego.Any.bool true else Rego.Any.bool false) = Rego.Any.bool false + ↔ cmp := by aesop + +@[simp] +theorem bool_comparison' (s₁ s₂ : String) : + ¬ (if s₁ = s₂ then Rego.Any.bool true else Rego.Any.bool false) = Rego.Any.bool false + ↔ s₁ = s₂ := by aesop + +theorem category_inv : + ∀ (attr : Attribute), + Rego.Any.deref (rego_of_attribute attr) (Rego.Any.str "category") = Rego.Any.str attr.category := by + intro attr + simp [Rego.Any.deref, rego_of_attribute] + match attr with + | { issuer := some issuer, .. } => + simp [Lean.AssocList.find?, Option.getD] + | { issuer := none, .. } => + simp [Lean.AssocList.find?, Option.getD] + +theorem designator_category_inv : + ∀ (attr : AttributeDesignator), + Rego.Any.deref (rego_of_attribute_designator attr) (Rego.Any.str "category") = Rego.Any.str attr.category := by + intro attr + simp [Rego.Any.deref, rego_of_attribute_designator] + match attr with + | { issuer := some issuer, .. } => + simp [Lean.AssocList.find?, Option.getD] + | { issuer := none, .. } => + simp [Lean.AssocList.find?, Option.getD] + +theorem identifier_inv : + ∀ (attr : Attribute), + Rego.Any.deref (rego_of_attribute attr) (Rego.Any.str "identifier") = Rego.Any.str attr.identifier := by + intro attr + simp [Rego.Any.deref, rego_of_attribute] + match attr with + | { issuer := some issuer, .. } => + simp [Lean.AssocList.find?, Option.getD] + | { issuer := none, .. } => + simp [Lean.AssocList.find?, Option.getD] + +theorem designator_identifier_inv : + ∀ (attr : AttributeDesignator), + Rego.Any.deref (rego_of_attribute_designator attr) (Rego.Any.str "identifier") = Rego.Any.str attr.identifier := by + intro attr + simp [Rego.Any.deref, rego_of_attribute_designator] + match attr with + | { issuer := some issuer, .. } => + simp [Lean.AssocList.find?, Option.getD] + | { issuer := none, .. } => + simp [Lean.AssocList.find?, Option.getD] + +theorem value_inv : + ∀ (attr : Attribute), + Rego.Any.deref (rego_of_attribute attr) (Rego.Any.str "value") = rego_of_primitive attr.value := by + intro attr + simp [Rego.Any.deref, rego_of_attribute] + match attr with + | { issuer := some issuer, .. } => + simp [Lean.AssocList.find?, Option.getD] + | { issuer := none, .. } => + simp [Lean.AssocList.find?, Option.getD] + +theorem designator_type_inv : + ∀ (attr : AttributeDesignator), + Rego.Any.deref (rego_of_attribute_designator attr) (Rego.Any.str "type") = + Rego.Any.str (string_of_xmltype attr.type) := by + intro attr + simp [Rego.Any.deref, rego_of_attribute_designator] + match attr with + | { issuer := some issuer, .. } => + simp [Lean.AssocList.find?, Option.getD] + | { issuer := none, .. } => + simp [Lean.AssocList.find?, Option.getD] + +theorem value_type_inv : + ∀ (attr : Attribute), + Rego.Any.deref (rego_of_primitive attr.value) (Rego.Any.str "type") = + Rego.Any.str (string_of_xmltype attr.value.fst) := by + intro attr + simp [Rego.Any.deref, rego_of_attribute_designator, rego_of_primitive] + match attr with + | { value := (type, inner), issuer := some _, .. } => + simp [Lean.AssocList.find?, Option.getD] + | { value := (type, inner), issuer := none, .. } => + simp [Lean.AssocList.find?, Option.getD] + +theorem issuer_none : + ∀ (attr : Attribute), + ((Rego.Any.deref (rego_of_attribute attr) (Rego.Any.str "issuer") == Rego.Any.null) = true) -> + attr.issuer = none := by + intro attr + simp [Rego.Any.deref, rego_of_attribute] + match attr with + | { issuer := some issuer, .. } => + simp [Lean.AssocList.find?, Option.getD] + intro h + contradiction + | { identifier := identifier, issuer := none, .. } => + simp [Lean.AssocList.find?, Option.getD] + +theorem str_str_eq : + ∀ (s₁ s₂ : String), + (Rego.Any.str s₁ == Rego.Any.str s₂) = true → s₁ = s₂ := by + intros s₁ s₂ h + have hint : (Rego.Any.str s₁ == Rego.Any.str s₂) = (s₁ == s₂) := by rfl + simp [hint] at h + exact h + +theorem attr_type_inv : + ∀ (attr : Attribute), + Rego.Any.deref (Rego.Any.deref (rego_of_attribute attr) (Rego.Any.str "value")) (Rego.Any.str "type") + = Rego.Any.str (string_of_xmltype attr.value.fst) := by + intro attr + simp [Rego.Any.deref, rego_of_attribute] + match attr with + | { issuer := some issuer, value, .. } => + simp [Lean.AssocList.find?, Option.getD] + unfold rego_of_primitive + match value with + | (fst, snd) => simp [Lean.AssocList.find?] + | { issuer := none, value, .. } => + simp [Lean.AssocList.find?, Option.getD] + unfold rego_of_primitive + match value with + | (fst, snd) => simp [Lean.AssocList.find?] + +theorem issuer_inv_eq : + ∀ (attr : Attribute) (desg : AttributeDesignator), + (Rego.Any.deref (rego_of_attribute attr) (Rego.Any.str "issuer") == + Rego.Any.deref (rego_of_attribute_designator desg) (Rego.Any.str "issuer")) = true + → attr.issuer = desg.issuer := by + intros attr desg + simp [Rego.Any.deref, rego_of_attribute, rego_of_attribute_designator] + match attr with + | { issuer := some issuer, .. } => + match desg with + | { issuer := some issuer', .. } => + simp [Option.getD, Lean.AssocList.find?] + | { issuer := none, .. } => + intro h + contradiction + | { issuer := none, .. } => + match desg with + | { issuer := some issuer', .. } => + intro h + contradiction + | { issuer := none, .. } => + simp [Option.getD, Lean.AssocList.find?] + +theorem issuer_inv_eq' : + ∀ (attr : Attribute) (desg : AttributeDesignator), + attr.issuer = desg.issuer → + (Rego.Any.deref (rego_of_attribute attr) (Rego.Any.str "issuer") == + Rego.Any.deref (rego_of_attribute_designator desg) (Rego.Any.str "issuer")) = true := by + intros attr desg + simp [Rego.Any.deref, rego_of_attribute, rego_of_attribute_designator] + match attr with + | { issuer := some issuer, .. } => + match desg with + | { issuer := some issuer', .. } => + simp [Option.getD, Lean.AssocList.find?] + | { issuer := none, .. } => + intro h + contradiction + | { issuer := none, .. } => + match desg with + | { issuer := some issuer', .. } => + intro h + contradiction + | { issuer := none, .. } => + simp [Option.getD, Lean.AssocList.find?] + +theorem string_of_xmltype_inj : + ∀ (t₁ t₂ : XmlType), + (string_of_xmltype t₁) = (string_of_xmltype t₂) → t₁ = t₂ := by + intros t₁ t₂ + cases t₁ <;> { cases t₂ <;> simp [string_of_xmltype] } + +theorem string_of_xmltype_functional : + ∀ (t₁ t₂ : XmlType), + t₁ = t₂ → (string_of_xmltype t₁) = (string_of_xmltype t₂) := by + intros t₁ t₂ + cases t₁ <;> { cases t₂ <;> simp [string_of_xmltype] } + +theorem inv_issuer (issuer : String) : + attr.issuer = some issuer → + (Rego.Any.deref (rego_of_attribute attr) (Rego.Any.str "issuer") == + Rego.Any.str issuer) = true := by + simp [Rego.Any.deref, rego_of_attribute] + match attr with + | { issuer := some issuer, .. } => + simp [Option.getD, Lean.AssocList.find?] + | { issuer := none, .. } => + intro h + contradiction + +theorem inv_issuer_none : + attr.issuer = none → + (Rego.Any.deref (rego_of_attribute attr) (Rego.Any.str "issuer") == + Rego.Any.null) = true := by + intro h + simp [Rego.Any.deref, rego_of_attribute] + match attr with + | { issuer := some issuer, .. } => + contradiction + | { issuer := none, .. } => + simp [Option.getD, Lean.AssocList.find?] + +-- theorem inv_value_type : +-- attr.value.fst = designator.type → +-- (Rego.Any.deref (Rego.Any.deref (rego_of_attribute attr) (Rego.Any.str "value")) (Rego.Any.str "type") == +-- Rego.Any.deref (rego_of_attribute_designator designator) (Rego.Any.str "type")) = +-- true := by +-- intro h +-- simp [Rego.Any.deref, rego_of_attribute] +-- match attr with +-- | { issuer := some issuer, .. } => +-- simp [Option.getD, Lean.AssocList.find?] +-- sorry +-- | { issuer := none, .. } => +-- simp [Option.getD, Lean.AssocList.find?] +-- sorry + +theorem designator_matches_correct : + ∀ (designator : AttributeDesignator) (attr : Attribute), + designator_matches + (rego_of_attribute_designator designator) + (rego_of_attribute attr) + (Rego.Any.bool true) + ↔ + attribute_matches designator attr := by + intros designator attr + rw [iff_iff_implies_and_implies] + apply And.intro + { intro h + cases h with + | rule0 h => + let h₂ := h.right.left + let h₃ := h.right.right.left + let h₄ := h.right.right.right.left + let h₅ := h.right.right.right.right + + unfold attribute_matches + simp [eq, equal, Rego.Any.deref] + + apply And.intro + { simp [category_inv, designator_category_inv, equal] at h₅ + exact h₅ } + { apply And.intro + { simp [identifier_inv, designator_identifier_inv, equal] at h₄ + exact h₄ } + { apply And.intro + { simp [equal, value_inv, designator_type_inv, value_type_inv] at h₃ + apply string_of_xmltype_inj + exact h₃ } + { apply Or.inl + apply issuer_none + simp [equal] at h₂ + exact h₂ }}} + | rule1 h => + let h₂ := h.right.left + let h₃ := h.right.right.left + let h₄ := h.right.right.right.left + let h₅ := h.right.right.right.right + + unfold attribute_matches + simp [eq, equal, Rego.Any.deref] + + apply And.intro + { simp [category_inv, designator_category_inv, equal] at h₅ + exact h₅ } + { apply And.intro + { simp [identifier_inv, designator_identifier_inv, equal] at h₄ + exact h₄ } + { apply And.intro + { simp [equal, value_inv, designator_type_inv, value_type_inv] at h₃ + apply string_of_xmltype_inj + exact h₃ } + { apply Or.inr + simp [equal] at h₂ + apply issuer_inv_eq + exact h₂ }}}} + { unfold attribute_matches + simp + intros hcat hident htyp hissuer + cases hissuer with + | inl hissuer => + apply designator_matches.rule0 + apply And.intro + { simp [eq] } + { apply And.intro + { simp [equal] + apply inv_issuer_none + assumption } + { apply And.intro + { simp [equal, designator_type_inv, attr_type_inv] + apply string_of_xmltype_functional + assumption } + { apply And.intro + { simp [equal, identifier_inv, designator_identifier_inv] + assumption } + { simp [equal, category_inv, designator_category_inv] + assumption }}}} + | inr hissuer => + apply designator_matches.rule1 + apply And.intro + { simp [eq] } + { apply And.intro + { simp [equal] + apply issuer_inv_eq' + assumption } + { apply And.intro + { simp [equal, designator_type_inv, attr_type_inv] + apply string_of_xmltype_functional + assumption } + { apply And.intro + { simp [equal, identifier_inv, designator_identifier_inv] + assumption } + { simp [equal, category_inv, designator_category_inv] + assumption }}}} } + + +-- def rego_error := (∀ (vargs__40 : Rego.Any), ∃! (vvalue__41 : Rego.Any), (eq (designator_matches vargs__40) vvalue__41)) + +-- #eval Rego.Any.deref (rego_of_attribute (Attribute.mk "a" "b" "c" (XmlType.boolean, "true"))) (Rego.Any.str "issuer") + +inductive q (vx__0 : Rego.Any) where + | rule0 : ∃ (vinternal__15 vsites__16 vsite__17 : Rego.Any), + (And (Ne (eq vx__0 (Rego.Any.deref vsite__17 (Rego.Any.str "name"))) (Rego.Any.bool False)) + (Ne (vsites__16.contains vsite__17) (Rego.Any.bool False))) → q vx__0 +def rego_error := (False) diff --git a/rego-proofs/Rego/lake-manifest.json b/rego-proofs/Rego/lake-manifest.json index 9b0ab31..639b42c 100644 --- a/rego-proofs/Rego/lake-manifest.json +++ b/rego-proofs/Rego/lake-manifest.json @@ -1,27 +1,52 @@ -{"version": 4, +{"version": 6, "packagesDir": "lake-packages", "packages": [{"git": - {"url": "https://github.com/leanprover-community/mathlib4.git", + {"url": "https://github.com/leanprover-community/aesop", "subDir?": null, - "rev": "f85368f49bea5a60679f40625f31177479d7f732", + "rev": "0654e7a1ba1542c3a24f936e52a40b3fee6c13c0", + "opts": {}, + "name": "aesop", + "inputRev?": "v4.2.0", + "inherited": false}}, + {"git": + {"url": "https://github.com/leanprover-community/mathlib4", + "subDir?": null, + "rev": "753159252c585df6b6aa7c48d2b8828d58388b79", + "opts": {}, "name": "mathlib", - "inputRev?": null}}, + "inputRev?": "v4.2.0", + "inherited": false}}, + {"git": + {"url": "https://github.com/leanprover/std4", + "subDir?": null, + "rev": "409a644492aaff846b6b2963e221c7f1ceaf30cc", + "opts": {}, + "name": "std", + "inputRev?": "v4.2.0", + "inherited": true}}, {"git": - {"url": "https://github.com/gebner/quote4", + {"url": "https://github.com/leanprover-community/quote4", "subDir?": null, - "rev": "7ae096b232087096ff0243a2b70d32720d2621ae", + "rev": "a387c0eb611857e2460cf97a8e861c944286e6b2", + "opts": {}, "name": "Qq", - "inputRev?": "master"}}, + "inputRev?": "master", + "inherited": true}}, {"git": - {"url": "https://github.com/JLimperg/aesop", + {"url": "https://github.com/leanprover/lean4-cli", "subDir?": null, - "rev": "071464ac36e339afb7a87640aa1f8121f707a59a", - "name": "aesop", - "inputRev?": "master"}}, + "rev": "39229f3630d734af7d9cfb5937ddc6b41d3aa6aa", + "opts": {}, + "name": "Cli", + "inputRev?": "nightly", + "inherited": true}}, {"git": - {"url": "https://github.com/leanprover/std4", + {"url": "https://github.com/leanprover-community/ProofWidgets4", "subDir?": null, - "rev": "5507f9d8409f93b984ce04eccf4914d534e6fca2", - "name": "std", - "inputRev?": "main"}}]} + "rev": "f1a5c7808b001305ba07d8626f45ee054282f589", + "opts": {}, + "name": "proofwidgets", + "inputRev?": "v0.0.21", + "inherited": true}}], + "name": "rego"} diff --git a/rego-proofs/Rego/lakefile.lean b/rego-proofs/Rego/lakefile.lean index acc69c1..9163884 100644 --- a/rego-proofs/Rego/lakefile.lean +++ b/rego-proofs/Rego/lakefile.lean @@ -1,14 +1,10 @@ import Lake open Lake DSL -package «rego» { - -- add any package configuration options here -} - -require mathlib from git - "https://github.com/leanprover-community/mathlib4.git" +package rego @[default_target] -lean_lib «Rego» { - -- add any library configuration options here -} +lean_lib Rego + +require aesop from git "https://github.com/leanprover-community/aesop"@"v4.2.0" +require mathlib from git "https://github.com/leanprover-community/mathlib4"@"v4.2.0" diff --git a/rego-proofs/Rego/lean-toolchain b/rego-proofs/Rego/lean-toolchain new file mode 100644 index 0000000..2f868c6 --- /dev/null +++ b/rego-proofs/Rego/lean-toolchain @@ -0,0 +1 @@ +leanprover/lean4:v4.2.0 diff --git a/rego-proofs/compiler-rewrite/lib/compiler.ml b/rego-proofs/compiler-rewrite/lib/compiler.ml index 03f37d0..3b0384a 100644 --- a/rego-proofs/compiler-rewrite/lib/compiler.ml +++ b/rego-proofs/compiler-rewrite/lib/compiler.ml @@ -10,7 +10,6 @@ type definition_kind = Complete | FunctionRule [@@deriving eq, show] - let fold_or props = match List.reduce props ~f:(fun x y -> Application (Identifier "Or", [y; x])) with | Some x -> x @@ -21,6 +20,9 @@ let fold_and props = | Some x -> x | None -> Bool false +let fold_deref terms = + List.reduce_exn terms ~f:(fun x y -> Application (Identifier "Rego.Any.deref", [x; y])) + let kind_and_args_of_rule = function | { head = ((_, []), Assignment (_, term)); _ } -> `ScalarRule term @@ -259,7 +261,7 @@ let rec compile_term env : term -> lean_expression = let terms' = List.map ~f:(compile_term env) terms in if List.is_empty terms' then target' - else Application (Identifier "Rego.Any.deref", [target'] @ terms') + else [target'] @ terms' |> fold_deref | Array xs -> let xs' = List.map ~f:(compile_term env) xs in Application (Identifier "Rego.Any.array", xs') diff --git a/xacml-proofs/.gitignore b/xacml-proofs/.gitignore index 4aab16c..d5138da 100644 --- a/xacml-proofs/.gitignore +++ b/xacml-proofs/.gitignore @@ -1 +1,3 @@ xacml-3.0-from-2.0-ct/ +.lake/ +_build/ diff --git a/xacml-proofs/compiler/bin/dune b/xacml-proofs/compiler/bin/dune index 3d787bf..6b16152 100644 --- a/xacml-proofs/compiler/bin/dune +++ b/xacml-proofs/compiler/bin/dune @@ -1,4 +1,5 @@ -(executable - (public_name compiler) - (name main) - (libraries core compiler)) +(executables + (public_names compiler request_compiler) + (names main request) + (libraries core compiler)) + diff --git a/xacml-proofs/compiler/bin/main.ml b/xacml-proofs/compiler/bin/main.ml index 946d65d..80a4844 100644 --- a/xacml-proofs/compiler/bin/main.ml +++ b/xacml-proofs/compiler/bin/main.ml @@ -5,4 +5,4 @@ let () = let argv = Sys.get_argv () in let file_names = Array.sub argv ~pos:1 ~len:(Array.length argv - 1) |> Array.to_list in let policy_code = List.map file_names ~f:In_channel.read_all in - compile' policy_code |> Stdio.print_endline + compile_policies policy_code |> Stdio.print_endline diff --git a/xacml-proofs/compiler/bin/request.ml b/xacml-proofs/compiler/bin/request.ml new file mode 100644 index 0000000..74b9169 --- /dev/null +++ b/xacml-proofs/compiler/bin/request.ml @@ -0,0 +1,8 @@ +open Core +open Compiler + +let () = + let argv = Sys.get_argv () in + let file_name = Array.get argv 1 in + let policy_code = In_channel.read_all file_name in + compile_request policy_code |> Stdio.print_endline diff --git a/xacml-proofs/compiler/lib/compiler.ml b/xacml-proofs/compiler/lib/compiler.ml index 73ecd6e..7a18643 100644 --- a/xacml-proofs/compiler/lib/compiler.ml +++ b/xacml-proofs/compiler/lib/compiler.ml @@ -7,7 +7,8 @@ let version_match_type_regex = Str.regexp "^\\(\\(\\d+|\\*\\)\\.\\)*\\(\\d+|\\*| type xml_element = (string * (string * string) list * Xml.xml list) -type lean_expression = Identifier of string +type lean_expression = Eval of lean_expression + | Identifier of string | Bool of bool | String of string (* | Number of int *) @@ -17,6 +18,7 @@ type lean_expression = Identifier of string | Define of string * lean_expression let rec fmt_lean_expression : lean_expression -> string = function + | Eval expr -> (Printf.sprintf "#eval %s" (fmt_lean_expression expr)) | Identifier s -> s | Bool b -> if b then "True" else "False" | String s -> Printf.sprintf "\"%s\"" s @@ -202,11 +204,19 @@ let rec compile_expression let (tag_name, attrs, children) = elt in match tag_name with | "Apply" -> - let args = List.filter_map children ~f:(function - | Element ("Description", _, _) -> None - | Element elt -> Some (compile_expression env elt) - | _ -> None) in - Application (Identifier "Expression.apply", args) + (match get_attr "FunctionId" attrs with + | None -> + let args = List.filter_map children ~f:(function + | Element ("Description", _, _) -> None + | Element elt -> Some (compile_expression env elt) + | _ -> None) in + Application (Identifier "Expression.apply", args) + | Some name -> + let args = List.filter_map children ~f:(function + | Element ("Description", _, _) -> None + | Element elt -> Some (compile_expression env elt) + | _ -> None) in + Application (Identifier "Expression.apply", String name :: args)) | "Function" -> let name = get_attr_exn "FunctionID" attrs in Application (Identifier "Expression.function", [String name]) @@ -528,7 +538,7 @@ let rec compile_policyset | Some identifier -> Some { metadata_definitions = []; element_definitions = []; - root_identifier = identifier; + root_identifier = (Printf.sprintf "%s_element" identifier); edges = [] } | _ -> failwith (Printf.sprintf "unbound reference to %s" identifier)) | Element (("Policy", _, _) as elt) -> Some (compile_policy elt) @@ -541,7 +551,7 @@ let rec compile_policyset | Some identifier -> Some { metadata_definitions = []; element_definitions = []; - root_identifier = identifier; + root_identifier = (Printf.sprintf "%s_element" identifier); edges = [] } | _ -> failwith (Printf.sprintf "unbound reference to %s" identifier)) | _ -> None) @@ -624,7 +634,16 @@ let compile policy_elements : Xml.xml -> lean_expression list = function element_definitions) | _ -> failwith "failed to order definitions") in - metadata_definitions @ element_definitions @ [Identifier root_identifier] + metadata_definitions + @ element_definitions + @ [Eval + (Application (Identifier "IO.println", + [(Application (Identifier "xml_of_response", + [Application (Identifier "Result'.eval", + [Application (Identifier "ElementTree.eval", + [Identifier "request"; + Identifier root_identifier]); + Identifier "request"])]))]))] | PCData s -> failwith s let xml_element_of_Xml : Xml.xml -> xml_element = function @@ -632,7 +651,7 @@ let xml_element_of_Xml : Xml.xml -> xml_element = function | _ -> failwith "not an element" -let compile' (policies : string list) : string = +let compile_policies (policies : string list) : string = let policies = List.map ~f:Xml.parse_string policies in let policy_elements = List.map ~f:xml_element_of_Xml policies |> List.map ~f:policy_element_names @@ -643,3 +662,67 @@ let compile' (policies : string list) : string = |> List.concat |> List.map ~f:fmt_lean_expression |> String.concat ~sep:"\n" + +(* --- *) + +let xml_type_of_string : string -> lean_expression = function + | "http://www.w3.org/2001/XMLSchema#string" -> Identifier "XmlType.string" + | "http://www.w3.org/2001/XMLSchema#boolean" -> Identifier "XmlType.boolean" + | "http://www.w3.org/2001/XMLSchema#integer" -> Identifier "XmlType.integer" + | "http://www.w3.org/2001/XMLSchema#double" -> Identifier "XmlType.double" + | "http://www.w3.org/2001/XMLSchema#time" -> Identifier "XmlType.time" + | "http://www.w3.org/2001/XMLSchema#date" -> Identifier "XmlType.date" + | "http://www.w3.org/2001/XMLSchema#dateTime" -> Identifier "XmlType.dateTime" + | "http://www.w3.org/2001/XMLSchema#dayTimeDuration" -> Identifier "XmlType.dayTimeDuration" + | "http://www.w3.org/2001/XMLSchema#yearMonthDuration" -> Identifier "XmlType.yearMonthDuration" + | "http://www.w3.org/2001/XMLSchema#anyURI" -> Identifier "XmlType.anyURI" + | "http://www.w3.org/2001/XMLSchema#hexBinary" -> Identifier "XmlType.hexBinary" + | "http://www.w3.org/2001/XMLSchema#base64Binary" -> Identifier "XmlType.base64Binary" + | "urn:oasis:names:tc:xacml:1.0:data-type:rfc822Name" -> Identifier "XmlType.rfc822Name" + | "urn:oasis:names:tc:xacml:1.0:data-type:x500Name" -> Identifier "XmlType.x500Name" + | "urn:oasis:names:tc:xacml:2.0:data-type:ipAddress" -> Identifier "XmlType.ipAddress" + | "urn:oasis:names:tc:xacml:2.0:data-type:dnsName" -> Identifier "XmlType.dnsName" + | s -> failwith (Printf.sprintf "unsupported type: (%s)" s) + +let compile_attribute_value category identifier issuer ((tag_name, attributes, children) : xml_element) : lean_expression list = + assert String.(tag_name = "AttributeValue"); + let typ = get_attr_exn "DataType" attributes in + match children with + | [PCData s] -> + [Application (Identifier "Attribute.mk", + [String category; + String identifier; + (match issuer with + | Some issuer -> Application (Identifier "some", [String issuer]) + | None -> Identifier "none"); + Tuple [xml_type_of_string typ; String s]])] + | _ -> failwith "ill-formed attribute value" + +let compile_attribute category ((tag_name, attributes, children) : xml_element) : lean_expression list = + assert String.(tag_name = "Attribute"); + let identifier = get_attr_exn "AttributeId" attributes in + let issuer = get_attr "Issuer" attributes in + compile_attribute_value category identifier issuer (List.nth_exn children 0 |> xml_element_of_Xml) + +let compile_attributes ((tag_name, attributes, children) : xml_element) : lean_expression list = + assert String.(tag_name = "Attributes"); + let category = get_attr_exn "Category" attributes in + children + |> xml_element_of_children + |> List.map ~f:(compile_attribute category) + |> List.concat + +let compile_request' : Xml.xml -> lean_expression list = function + | Element (("Request", _attributes, children)) -> + List.map ~f:xml_element_of_Xml children + |> List.map ~f:compile_attributes + |> List.concat + | Element ((tag_name, _, _)) -> + failwith (Printf.sprintf "(%s)" tag_name) + | PCData s -> failwith s + +let compile_request (request : string) : string = + let request = Xml.parse_string request in + let attributes = compile_request' request in + Define ("request", List attributes) + |> fmt_lean_expression diff --git a/xacml-proofs/compiler/lib/compiler.mli b/xacml-proofs/compiler/lib/compiler.mli index 0106059..41f2613 100644 --- a/xacml-proofs/compiler/lib/compiler.mli +++ b/xacml-proofs/compiler/lib/compiler.mli @@ -1 +1,2 @@ -val compile' : string list -> string +val compile_policies : string list -> string +val compile_request : string -> string diff --git a/xacml-proofs/lean/lake-manifest.json b/xacml-proofs/lean/lake-manifest.json new file mode 100644 index 0000000..083ac34 --- /dev/null +++ b/xacml-proofs/lean/lake-manifest.json @@ -0,0 +1,59 @@ +{"version": 7, + "packagesDir": ".lake/packages", + "packages": + [{"url": "https://github.com/leanprover/std4", + "type": "git", + "subDir": null, + "rev": "2e4a3586a8f16713f16b2d2b3af3d8e65f3af087", + "name": "std", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.3.0", + "inherited": false, + "configFile": "lakefile.lean"}, + {"url": "https://github.com/leanprover-community/aesop", + "type": "git", + "subDir": null, + "rev": "76c4ea44190682335028ed12a23241ccf95294d0", + "name": "aesop", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.3.0", + "inherited": false, + "configFile": "lakefile.lean"}, + {"url": "https://github.com/leanprover-community/quote4", + "type": "git", + "subDir": null, + "rev": "d3a1d25f3eba0d93a58d5d3d027ffa78ece07755", + "name": "Qq", + "manifestFile": "lake-manifest.json", + "inputRev": "master", + "inherited": true, + "configFile": "lakefile.lean"}, + {"url": "https://github.com/leanprover-community/ProofWidgets4", + "type": "git", + "subDir": null, + "rev": "909febc72b4f64628f8d35cd0554f8a90b6e0749", + "name": "proofwidgets", + "manifestFile": "lake-manifest.json", + "inputRev": "v0.0.23", + "inherited": true, + "configFile": "lakefile.lean"}, + {"url": "https://github.com/leanprover/lean4-cli", + "type": "git", + "subDir": null, + "rev": "a751d21d4b68c999accb6fc5d960538af26ad5ec", + "name": "Cli", + "manifestFile": "lake-manifest.json", + "inputRev": "main", + "inherited": true, + "configFile": "lakefile.lean"}, + {"url": "https://github.com/leanprover-community/mathlib4", + "type": "git", + "subDir": null, + "rev": "f04afed5ac9fea0e1355bc6f6bee2bd01f4a888d", + "name": "mathlib", + "manifestFile": "lake-manifest.json", + "inputRev": "v4.3.0", + "inherited": false, + "configFile": "lakefile.lean"}], + "name": "xacml", + "lakeDir": ".lake"} diff --git a/xacml-proofs/lean/lakefile.lean b/xacml-proofs/lean/lakefile.lean new file mode 100644 index 0000000..cdcaaa8 --- /dev/null +++ b/xacml-proofs/lean/lakefile.lean @@ -0,0 +1,11 @@ +import Lake +open Lake DSL + +package xacml + +@[default_target] +lean_lib Xacml + +require aesop from git "https://github.com/leanprover-community/aesop"@"v4.3.0" +require std from git "https://github.com/leanprover/std4"@"v4.3.0" +require mathlib from git "https://github.com/leanprover-community/mathlib4"@"v4.3.0" diff --git a/xacml-proofs/lean/lean-toolchain b/xacml-proofs/lean/lean-toolchain new file mode 100644 index 0000000..5cadc9d --- /dev/null +++ b/xacml-proofs/lean/lean-toolchain @@ -0,0 +1 @@ +leanprover/lean4:v4.3.0 diff --git a/xacml-proofs/modeling-choices.org b/xacml-proofs/modeling-choices.org deleted file mode 100644 index 8d88c61..0000000 --- a/xacml-proofs/modeling-choices.org +++ /dev/null @@ -1,118 +0,0 @@ -XACML makes use of URIs and strings as identifiers. When such identifiers are compared for equality, the comparison MUST be done so that the identifiers are equal if they have the same length and the characters in the two identifiers are equal codepoint by codepoint. - -(This is equivalent to string equality in Lean.) - -* Modeling Exceptions - -7.19 Exception handling specifies that an indeterminate decision is returned and a statuscode is set. - StatusCode is, however, optional. - -* In Scope vs Out of Scope - -"We would like to be as complete as possible, so as to ensure that this can be leveraged to prove a refinement of a policy down to the status codes, obligations, and advice it returns." - -** Not Relevant - -- [ ] Element <Description> (no semantic meaning) -- [ ] Element <PolicyIssuer> (XMLAdmin) -- [ ] Element <PolicySetDefaults> (optional) -- [ ] Element <XPathVersion> (optional) -- [ ] Element <PolicySetIdReference> (dissolved by compiler translation) -- [ ] Element <PolicyIdReference> (dissolved by compiler translation) -- [ ] Simple type VersionType (dissolved by compiler translation) -- [ ] Simple type VersionMatchType (dissolved by compiler translation) -- [ ] Element <PolicyDefaults> (optional) -- [ ] Element <CombinerParameters> (optional) -- [ ] Element <CombinerParameter> (optional) -- [ ] Element <RuleCombinerParameters> (optional) -- [ ] Element <PolicyCombinerParameters> (optional) -- [ ] Element <PolicySetCombinerParameters> (optional) -- [ ] Element <AttributeSelector> (dissolved by compiler translation) -- [ ] Element <RequestDefaults> (optional) -- [ ] Element <PolicyIdentifierList> (optional) -- [ ] Element <MultiRequests> (optional) -- [ ] Element <RequestReference> (optional) -- [ ] Element <AttributesReference> (optional) -- [ ] Element <StatusMessage> (optional) -- [ ] Element <StatusDetail> (optional) -- [ ] Element <VariableDefinition> (dissolved by compiler translation) -- [ ] Element <VariableReference> (dissolved by compiler translation) -- [ ] Element <Content> (dissolved by compiler translation) - -** Modeled - -- [X] Element <PolicySet> -- [X] Element <Target> -- [X] Element <AnyOf> -- [X] Element <AllOf> -- [X] Element <Match> -- [X] Element <Policy> -- [X] Element <Rule> -- [ ] Simple type EffectType - - Same as Decision in Lean -- [ ] Element <Expression> -- [X] Element <Condition> - - Just an Expression per 5.26 -- [X] Element <Apply> -- [X] Element <Function> -- [ ] Element <AttributeDesignator> -- [ ] Element <AttributeValue> -- [X] Element <Request> -- [X] Element <Attributes> - - Category subsumed by individual attributes -- [ ] Element <Attribute> -- [X] Element <Response> -- [X] Element <Result> -- [X] Element <Decision> -- [ ] Element <Obligations> -- [ ] Element <AssociatedAdvice> -- [ ] Element <Obligation> -- [ ] Element <Advice> -- [ ] Element <AttributeAssignment> -- [ ] Element <ObligationExpressions> -- [ ] Element <AdviceExpressions> -- [ ] Element <ObligationExpression> -- [ ] Element <AdviceExpression> -- [ ] Element <AttributeAssignmentExpression> -- [ ] Element <Status> -- [ ] Element <StatusCode> -- [ ] Element <MissingAttributeDetail> - -** Doesn't Line Up with ACES - -- Does use PolicySetDefaults and XPathVersion but it's just XPath 1.0. Probably safe to ignore and have our XPath implementation follow 1.0. - -* Policy Schema - -- PolicySetId isn't explicitly encoded in the PolicySet, that's just the name we'll give to it in the embedding. -- Not modeling MaxDelegationDepth (XACMLAdmin extension) -- No =CombinerParameters= because no combination algorithm uses them. -- No =PolicySetDefaults=, =PolicyDefaults= because they're optional - -Assume =PolicySetIdReference=, =PolicyIdReference= are turned into =PolicySet= and =Policy= respectively. -Same assumption about PolicySelector as logic paper. - -* Request -- RequestDefaults is excluded because it is specified by the standard to be optional. -- MultiRequests is excluded because it is specified by the standard to be optional. -- Always assume ReturnPolicyIdList is true - -** Attribute - -- Assume Attribute->Issuer has no effect on access control decision -- TODO What about Attribute->IncludeInResult? - -* 7.3.3 Multivalued attributes - -If a single <Attribute> element in a request context contains multiple <AttributeValue> child elements, then the bag of values resulting from evaluation of the <Attribute> element MUST be identical to the bag of values that results from evaluating a context in which each <AttributeValue> element appears in a separate <Attribute> element, each carrying identical meta-data. - -This is handled by the compiler. - -* Variable Substitution - -Functions SHALL NOT have side effects, as evaluation order cannot be guaranteed in a standard way. - -* Compiler Versus Embedding Decisions - -Example: =<AllOf>= and =<AnyOf>= are specified to be nonempty. -We could encode this in Lean's type system but it's more convenient to assume that an empty =AllOf= or =AnyOf= will never be constructed by the trusted compiler base. diff --git a/xacml-translation/.gitignore b/xacml-translation/.gitignore new file mode 100644 index 0000000..69fa449 --- /dev/null +++ b/xacml-translation/.gitignore @@ -0,0 +1 @@ +_build/ diff --git a/xacml-translation/designator.rego b/xacml-translation/designator.rego new file mode 100644 index 0000000..2497ff9 --- /dev/null +++ b/xacml-translation/designator.rego @@ -0,0 +1,17 @@ +package experiment + +import future.keywords.if + +designator_matches(designator, attribute) if { + attribute.category == designator.category + attribute.identifier == designator.identifier + attribute.value.type == designator.type + attribute.issuer == null +} + +designator_matches(designator, attribute) if { + attribute.category == designator.category + attribute.identifier == designator.identifier + attribute.value.type == designator.type + attribute.issuer == designator.issuer +} diff --git a/xacml-translation/json_xacml_translator/bin/dune b/xacml-translation/json_xacml_translator/bin/dune new file mode 100644 index 0000000..1e39d81 --- /dev/null +++ b/xacml-translation/json_xacml_translator/bin/dune @@ -0,0 +1,4 @@ +(executable + (public_name json_xacml_translator) + (name main) + (libraries core translator)) diff --git a/xacml-translation/json_xacml_translator/bin/main.ml b/xacml-translation/json_xacml_translator/bin/main.ml new file mode 100644 index 0000000..3ccaf71 --- /dev/null +++ b/xacml-translation/json_xacml_translator/bin/main.ml @@ -0,0 +1,8 @@ +open Core +open Translator + +let () = + let argv = Sys.get_argv () in + let file_name = Array.get argv 1 in + let request_code = In_channel.read_all file_name in + compile_request request_code |> Stdio.print_endline diff --git a/xacml-translation/json_xacml_translator/dune-project b/xacml-translation/json_xacml_translator/dune-project new file mode 100644 index 0000000..ecdddec --- /dev/null +++ b/xacml-translation/json_xacml_translator/dune-project @@ -0,0 +1,26 @@ +(lang dune 3.11) + +(name json_xacml_translator) + +(generate_opam_files true) + +(source + (github username/reponame)) + +(authors "Author Name") + +(maintainers "Maintainer Name") + +(license LICENSE) + +(documentation https://url/to/documentation) + +(package + (name json_xacml_translator) + (synopsis "A short synopsis") + (description "A longer description") + (depends ocaml dune) + (tags + (topics "to describe" your project))) + +; See the complete stanza docs at https://dune.readthedocs.io/en/stable/dune-files.html#dune-project diff --git a/xacml-translation/json_xacml_translator/json_xacml_translator.opam b/xacml-translation/json_xacml_translator/json_xacml_translator.opam new file mode 100644 index 0000000..7b13bb9 --- /dev/null +++ b/xacml-translation/json_xacml_translator/json_xacml_translator.opam @@ -0,0 +1,31 @@ +# This file is generated by dune, edit dune-project instead +opam-version: "2.0" +synopsis: "A short synopsis" +description: "A longer description" +maintainer: ["Maintainer Name"] +authors: ["Author Name"] +license: "LICENSE" +tags: ["topics" "to describe" "your" "project"] +homepage: "https://github.com/username/reponame" +doc: "https://url/to/documentation" +bug-reports: "https://github.com/username/reponame/issues" +depends: [ + "ocaml" + "dune" {>= "3.11"} + "odoc" {with-doc} +] +build: [ + ["dune" "subst"] {dev} + [ + "dune" + "build" + "-p" + name + "-j" + jobs + "@install" + "@runtest" {with-test} + "@doc" {with-doc} + ] +] +dev-repo: "git+https://github.com/username/reponame.git" diff --git a/xacml-translation/json_xacml_translator/lib/dune b/xacml-translation/json_xacml_translator/lib/dune new file mode 100644 index 0000000..394a9e9 --- /dev/null +++ b/xacml-translation/json_xacml_translator/lib/dune @@ -0,0 +1,4 @@ +(library + (name translator) + (libraries base xml-light yojson) + (preprocess (pps ppx_let ppx_jane))) diff --git a/xacml-translation/json_xacml_translator/lib/translator.ml b/xacml-translation/json_xacml_translator/lib/translator.ml new file mode 100644 index 0000000..13125ab --- /dev/null +++ b/xacml-translation/json_xacml_translator/lib/translator.ml @@ -0,0 +1,81 @@ +open Base + +type xml_element = (string * (string * string) list * Xml.xml list) + +let rec get_attr (needle : string) : (string * string) list -> string option = function + | (k, v) :: xs -> if String.(k = needle) then Some v else get_attr needle xs + | _ -> None + +let get_exn opt message = + match opt with + | Some x -> x + | _ -> failwith message + +let get_attr_exn needle attrs : string = + get_exn (get_attr needle attrs) "missing attribute" + +let xml_element_of_children (children : Xml.xml list) : xml_element list = + List.map children ~f:(function + | Element x -> x + | _ -> failwith "called on element with non-element children") + +let xml_element_of_Xml : Xml.xml -> xml_element = function + | Element (elt) -> elt + | _ -> failwith "not an element" + +(* --- *) + +let compile_attribute_value category identifier issuer ((tag_name, attributes, children) : xml_element) = + assert String.(tag_name = "AttributeValue"); + let typ = get_attr_exn "DataType" attributes in + match children with + | [PCData s] -> + (match issuer with + | Some issuer -> + `Assoc + [ + ("category", `String category); + ("identifier", `String identifier); + ("issuer", `String issuer); + ("value", `Assoc [("kind", `String "primitive"); + ("type", `String typ); + ("value", `String s)]) + ] + | _ -> + `Assoc + [ + ("category", `String category); + ("identifier", `String identifier); + ("value", `Assoc [("kind", `String "primitive"); + ("type", `String typ); + ("value", `String s)]) + ]) + | _ -> failwith "ill-formed attribute value" + +let compile_attribute category ((tag_name, attributes, children) : xml_element) = + assert String.(tag_name = "Attribute"); + let identifier = get_attr_exn "AttributeId" attributes in + let issuer = get_attr "Issuer" attributes in + compile_attribute_value category identifier issuer (List.nth_exn children 0 |> xml_element_of_Xml) + +let compile_attributes ((tag_name, attributes, children) : xml_element) : _ = + assert String.(tag_name = "Attributes"); + let category = get_attr_exn "Category" attributes in + children + |> xml_element_of_children + |> List.map ~f:(compile_attribute category) + (* |> List.concat *) + +let compile_request' : Xml.xml -> _ = function + | Element (("Request", _attributes, children)) -> + List.map ~f:xml_element_of_Xml children + |> List.map ~f:compile_attributes + |> List.concat + | Element ((tag_name, _, _)) -> + failwith (Printf.sprintf "(%s)" tag_name) + | PCData s -> failwith s + +let compile_request (request : string) : string = + let request = Xml.parse_string request in + let attributes = compile_request' request in + Yojson.Basic.to_string (`List attributes) diff --git a/xacml-translation/json_xacml_translator/lib/translator.mli b/xacml-translation/json_xacml_translator/lib/translator.mli new file mode 100644 index 0000000..024211c --- /dev/null +++ b/xacml-translation/json_xacml_translator/lib/translator.mli @@ -0,0 +1 @@ +val compile_request : string -> string diff --git a/xacml-translation/json_xacml_translator/test/dune b/xacml-translation/json_xacml_translator/test/dune new file mode 100644 index 0000000..c75ecd9 --- /dev/null +++ b/xacml-translation/json_xacml_translator/test/dune @@ -0,0 +1,2 @@ +(test + (name json_xacml_translator)) diff --git a/xacml-translation/json_xacml_translator/test/json_xacml_translator.ml b/xacml-translation/json_xacml_translator/test/json_xacml_translator.ml new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/xacml-translation/json_xacml_translator/test/json_xacml_translator.ml |