Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add VariableDefinitions as optional elements in Rule (like in Policy) #3

Open
cdanger opened this issue Aug 21, 2023 · 9 comments
Open
Assignees
Labels
enhancement New feature or request

Comments

@cdanger
Copy link

cdanger commented Aug 21, 2023

See the pull request #10 for the proposed changes to the XACML 3.0 core spec (especially the tab Files changed) . This changes the XACML core XSD and therefore breaks compatibility with XACML 3.0.

See also @steven-legg 's alternative to maintain compatibility.

@steven-legg
Copy link

steven-legg commented Nov 15, 2023

What is the use case that motivates this enhancement?
A Rule doesn't appear on it's own in protocol messages; it is always wrapped in a Policy and inherits the VariableDefinition elements from that Policy. There is no ordering requirement between Rule and VariableDefinition elements so the VariableDefinitions that a Rule uses can immediately precede it. Visually there isn't much difference between having the VariableDefinitions just before or just after the <Rule> start tag.

@steven-legg
Copy link

Given that enhancements #1 and #2 would allow variable references in the Target it would make more sense for the VariableDefinition elements to appear before the Target.

@steven-legg
Copy link

The XML extension mechanism only allows us to add child elements at the end, so VariableDefinition elements would have to appear last, which isn't ideal.

The alternative to maintain compatibility with XACML 3.0 and use the same namespace would be to add all the changes we want into new elements for Rule, Policy and PolicySet, e.g., called AugmentedRule, AugmentedPolicy and AugmentedPolicySet, and allow Policy and PolicySet references to refer to either kind of policy or policy set. References only care about the ID. AugmentedPolicy could embed both Rule and AugmentedRule elements and AugmentedPolicySet could embed Policy, AugmentedPolicy, PolicySet and AugmentedPolicySet elements. One of the things I want to explore is flattening the structure by getting rid of PolicySet and letting Policy embed or reference other Policies, then we would only need AugmentedRule and AugmentedPolicy. Getting rid of Policy and letting PolicySet embed rules would amount to the same thing.

@cdanger
Copy link
Author

cdanger commented Nov 26, 2023

What is the use case that motivates this enhancement? A Rule doesn't appear on it's own in protocol messages; it is always wrapped in a Policy and inherits the VariableDefinition elements from that Policy. There is no ordering requirement between Rule and VariableDefinition elements so the VariableDefinitions that a Rule uses can immediately precede it. Visually there isn't much difference between having the VariableDefinitions just before or just after the <Rule> start tag.

The use case is for variables used in a Rule's Condition, Obligations or Advice (in order to simplify and/or optimize the Expressions) and for which the VariableDefinition - the value expression - depends on the Rule's Target. See the example of Policy down below.

Given that enhancements #1 and #2 would allow variable references in the Target it would make more sense for the VariableDefinition elements to appear before the Target.

Indeed, using VariableReferences in the Rule's Target is not my use case for this issue (I am fine with using the VariableDefinitions of the enclosing Policy for that). In my use case proposal, I need to use variables in Conditions, Obligations/Advice (not the Target), and their VariableDefinition expressions depend on the Rule's Target. That's why I put them after the Target.

Below is an example of Policy that we could write with VariableDefinitions in Rules . In this example, the VariableDefinitions for resource_classif_level, subject_classif_level, resource_cc_values[...] variables are different from one Rule to another (the Target is different) and they are used multiple times in the Rule's Condition.

<Policy PolicyId="Organisation_specific_P"
              Version="1.0"
              RuleCombiningAlgId="urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:deny-unless-permit">
         <Target/>
         <VariableDefinition VariableId="action_id">
            <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-one-and-only">
               <AttributeDesignator Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action"
                                    AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"
                                    DataType="http://www.w3.org/2001/XMLSchema#string"
                                    MustBePresent="true"/>
            </Apply>
         </VariableDefinition>

         <Rule RuleId="ACME_Company_R" Effect="Permit">
            <Description>
               Rule specific to ACME company's data protection policy.
               The ACME company is fictional, for illustration purposes only.
            </Description>
            <Target>
               <AnyOf>
                  <AllOf>
                     <Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                        <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">ACME</AttributeValue>
                        <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                                           Path="//*:PolicyIdentifier/text()"
                                           DataType="http://www.w3.org/2001/XMLSchema#string"
                                           MustBePresent="true"/>
                     </Match>
                  </AllOf>
               </AnyOf>
            </Target>
            <!-- Set the Variables to be used in the Condition - classification levels and other confidentiality category tags - according to ACME's policy. -->
            <VariableDefinition VariableId="resource_classif_level">
               <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only">
                  <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                                     DataType="http://www.w3.org/2001/XMLSchema#integer"
                                     MustBePresent="true"
                                     Path="if (//*:Classification = 'CONFIDENTIAL') then 3 else if (//*:Classification = 'INTERNAL') then 2 else if (//*:Classification = 'PUBLIC') then 1 else 0"/>
               </Apply>
            </VariableDefinition>
            <VariableDefinition VariableId="subject_classif_level">
               <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only">
                  <AttributeSelector Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
                                     DataType="http://www.w3.org/2001/XMLSchema#integer"
                                     MustBePresent="true"
                                     Path="if (//*:Classification = 'CONFIDENTIAL') then 3 else if (//*:Classification = 'INTERNAL') then 2 else if (//*:Classification = 'PUBLIC') then 1 else 0"/>
               </Apply>
            </VariableDefinition>
            <VariableDefinition VariableId="resource_cc_tags[Releasable To]">
               <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                                  Path="//*:Category[@TagName='Releasable To']/*:GenericValue/text()"
                                  DataType="http://www.w3.org/2001/XMLSchema#string"
                                  MustBePresent="false"/>
            </VariableDefinition>
            <VariableDefinition VariableId="resource_cc_tags[Sensitive]">
               <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                                  Path="//*:Category[@TagName='Sensitive']/*:GenericValue/text()"
                                  DataType="http://www.w3.org/2001/XMLSchema#string"
                                  MustBePresent="false"/>
            </VariableDefinition>

            <Condition>
               <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
                  <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:or">
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                           <VariableReference VariableId="action_id"/>
                           <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">READ</AttributeValue>
                        </Apply>
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal">
                           <VariableReference VariableId="subject_classif_level"/>
                           <VariableReference VariableId="resource_classif_level"/>
                        </Apply>
                     </Apply>
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                           <VariableReference VariableId="action_id"/>
                           <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">WRITE</AttributeValue>
                        </Apply>
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-less-than-or-equal">
                           <VariableReference VariableId="subject_classif_level"/>
                           <VariableReference VariableId="resource_classif_level"/>
                        </Apply>
                     </Apply>
                  </Apply>
                  <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:or">
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-equal">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-bag-size">
                           <VariableReference VariableId="resource_cc_tags[Releasable To]"/>
                        </Apply>
                        <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#integer">0</AttributeValue>
                     </Apply>
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-at-least-one-member-of">
                        <VariableReference VariableId="resource_cc_tags[Releasable To]"/>
                        <AttributeSelector Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
                                           Path="//*:Category[@TagName='Releasable To']/*:GenericValue/text()"
                                           DataType="http://www.w3.org/2001/XMLSchema#string"
                                           MustBePresent="false"/>
                     </Apply>
                  </Apply>
                  <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:or">
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-equal">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-bag-size">
                           <VariableReference VariableId="resource_cc_tags[Sensitive]"/>
                        </Apply>
                        <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#integer">0</AttributeValue>
                     </Apply>
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-subset">
                        <VariableReference VariableId="resource_cc_tags[Sensitive]"/>
                        <AttributeSelector Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
                                           Path="//*:Category[@TagName='Sensitive']/*:GenericValue/text()"
                                           DataType="http://www.w3.org/2001/XMLSchema#string"
                                           MustBePresent="false"/>
                     </Apply>
                  </Apply>
               </Apply>
            </Condition>
         </Rule>

         <Rule RuleId="Foo_Nation_R" Effect="Permit">
            <Description>
               Rule specific to "Foo" nation's data protection policy. The nation "Foo" is one of ACME company's clients.
               The Foo nation is fictional, for illustration purposes only.
            </Description>
            <Target>
               <AnyOf>
                  <AllOf>
                     <Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                        <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">FOO</AttributeValue>
                        <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                                           Path="//*:PolicyIdentifier/text()"
                                           DataType="http://www.w3.org/2001/XMLSchema#string"
                                           MustBePresent="true"/>
                     </Match>
                  </AllOf>
               </AnyOf>
            </Target>

            <!-- Set the Variables to be used in the Condition - classification levels and other confidentiality category tags - according to Foo Nation's policy. -->
            <VariableDefinition VariableId="resource_classif_level">
               <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only">
                  <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                                     DataType="http://www.w3.org/2001/XMLSchema#integer"
                                     MustBePresent="true"
                                     Path="if (//*:Classification = 'FOO SECRET') then 4 else if (//*:Classification = 'FOO CONFIDENTIAL') then 3 else if (//*:Classification = 'FOO RESTRICTED') then 2 else if (//*:Classification = 'FOO UNCLASSIFIED') then 1 else 0"/>
               </Apply>
            </VariableDefinition>
            <VariableDefinition VariableId="subject_classif_level">
               <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only">
                  <AttributeSelector Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
                                     DataType="http://www.w3.org/2001/XMLSchema#integer"
                                     MustBePresent="true"
                                     Path="if (//*:Classification = 'FOO SECRET') then 4 else if (//*:Classification = 'FOO CONFIDENTIAL') then 3 else if (//*:Classification = 'FOO RESTRICTED') then 2 else if (//*:Classification = 'FOO UNCLASSIFIED') then 1 else 0"/>
               </Apply>
            </VariableDefinition>
            <VariableDefinition VariableId="resource_cc_tags[Context]">
               <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                                  Path="//*:Category[@TagName='Context']/*:GenericValue/text()"
                                  DataType="http://www.w3.org/2001/XMLSchema#string"
                                  MustBePresent="false"/>
            </VariableDefinition>
            <VariableDefinition VariableId="resource_cc_tags[Only]">
               <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                                  Path="//*:Category[@TagName='Only']/*:GenericValue/text()"
                                  DataType="http://www.w3.org/2001/XMLSchema#string"
                                  MustBePresent="false"/>
            </VariableDefinition>
            <VariableDefinition VariableId="resource_cc_tags[Additional Sensitivity]">
               <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                                  Path="//*:Category[@TagName='Additional Sensitivity']/*:GenericValue/text()"
                                  DataType="http://www.w3.org/2001/XMLSchema#string"
                                  MustBePresent="false"/>
            </VariableDefinition>

            <!--
            etc.
            For brevity, Variables for other confidentiality categories are omitted here.
            -->

            <Condition>
               <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
                  <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:or">
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                           <VariableReference VariableId="action_id"/>
                           <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">READ</AttributeValue>
                        </Apply>
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal">
                           <VariableReference VariableId="subject_classif_level"/>
                           <VariableReference VariableId="resource_classif_level"/>
                        </Apply>
                     </Apply>
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                           <VariableReference VariableId="action_id"/>
                           <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">WRITE</AttributeValue>
                        </Apply>
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-less-than-or-equal">
                           <VariableReference VariableId="subject_classif_level"/>
                           <VariableReference VariableId="resource_classif_level"/>
                        </Apply>
                     </Apply>
                  </Apply>
                  <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:or">
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-equal">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-bag-size">
                           <VariableReference VariableId="resource_cc_tags[Context]"/>
                        </Apply>
                        <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#integer">0</AttributeValue>
                     </Apply>
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-subset">
                        <VariableReference VariableId="resource_cc_tags[Context]"/>
                        <AttributeSelector Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
                                           Path="//*:Category[@TagName='Context']/*:GenericValue/text()"
                                           DataType="http://www.w3.org/2001/XMLSchema#string"
                                           MustBePresent="false"/>
                     </Apply>
                  </Apply>
                  <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:or">
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-equal">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-bag-size">
                           <VariableReference VariableId="resource_cc_tags[Only]"/>
                        </Apply>
                        <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#integer">0</AttributeValue>
                     </Apply>
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-subset">
                        <VariableReference VariableId="resource_cc_tags[Only]"/>
                        <AttributeSelector Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
                                           Path="//*:Category[@TagName='Only']/*:GenericValue/text()"
                                           DataType="http://www.w3.org/2001/XMLSchema#string"
                                           MustBePresent="false"/>
                     </Apply>
                  </Apply>
                  <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:or">
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-equal">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-bag-size">
                           <VariableReference VariableId="resource_cc_tags[Additional Sensitivity]"/>
                        </Apply>
                        <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#integer">0</AttributeValue>
                     </Apply>
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-at-least-one-member-of">
                        <VariableReference VariableId="resource_cc_tags[Additional Sensitivity]"/>
                        <AttributeSelector Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
                                           Path="//*:Category[@TagName='Additional Sensitivity']/*:GenericValue/text()"
                                           DataType="http://www.w3.org/2001/XMLSchema#string"
                                           MustBePresent="false"/>
                     </Apply>
                  </Apply>

                  <!--
            etc.
            For brevity, Apply Expressions for other confidentiality categories are omitted here.
            -->

               </Apply>
            </Condition>
         </Rule>

         <Rule RuleId="EU_R" Effect="Permit">
            <Description>
               Rule specific to EU data protection policy, in case ACME Company is based in the EU.
               This example is for illustration purposes only, i.e. not official in any way.
            </Description>
            <Target>
               <AnyOf>
                  <AllOf>
                     <Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                        <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">EU</AttributeValue>
                        <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                                           Path="//*:PolicyIdentifier/text()"
                                           DataType="http://www.w3.org/2001/XMLSchema#string"
                                           MustBePresent="true"/>
                     </Match>
                  </AllOf>
               </AnyOf>
            </Target>

            <!-- Set the Variables to be used in the Condition - classification levels - according to EU policy. -->
            <VariableDefinition VariableId="resource_classif_level">
               <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only">
                  <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                                     DataType="http://www.w3.org/2001/XMLSchema#integer"
                                     MustBePresent="true"
                                     Path="if (//*:Classification = 'EU SECRET') then 4 else if (//*:Classification = 'EU CONFIDENTIAL') then 3 else if (//*:Classification = 'EU RESTRICTED') then 2 else if (//*:Classification = 'UNCLASSIFIED') then 1 else 0"/>
               </Apply>
            </VariableDefinition>
            <VariableDefinition VariableId="subject_classif_level">
               <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only">
                  <AttributeSelector Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
                                     DataType="http://www.w3.org/2001/XMLSchema#integer"
                                     MustBePresent="true"
                                     Path="if (//*:Classification = 'EU SECRET') then 4 else if (//*:Classification = 'EU CONFIDENTIAL') then 3 else if (//*:Classification = 'EU RESTRICTED') then 2 else if (//*:Classification = 'UNCLASSIFIED') then 1 else 0"/>
               </Apply>
            </VariableDefinition>

            <Condition>
               <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
                  <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:or">
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                           <VariableReference VariableId="action_id"/>
                           <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">READ</AttributeValue>
                        </Apply>
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal">
                           <VariableReference VariableId="subject_classif_level"/>
                           <VariableReference VariableId="resource_classif_level"/>
                        </Apply>
                     </Apply>
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                           <VariableReference VariableId="action_id"/>
                           <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">WRITE</AttributeValue>
                        </Apply>
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-less-than-or-equal">
                           <VariableReference VariableId="subject_classif_level"/>
                           <VariableReference VariableId="resource_classif_level"/>
                        </Apply>
                     </Apply>
                  </Apply>
               </Apply>
            </Condition>
         </Rule>
      </Policy>

@cdanger
Copy link
Author

cdanger commented Nov 26, 2023

The XML extension mechanism only allows us to add child elements at the end, so VariableDefinition elements would have to appear last, which isn't ideal.

The alternative to maintain compatibility with XACML 3.0 and use the same namespace would be to add all the changes we want into new elements for Rule, Policy and PolicySet, e.g., called AugmentedRule, AugmentedPolicy and AugmentedPolicySet, and allow Policy and PolicySet references to refer to either kind of policy or policy set. References only care about the ID. AugmentedPolicy could embed both Rule and AugmentedRule elements and AugmentedPolicySet could embed Policy, AugmentedPolicy, PolicySet and AugmentedPolicySet elements.

I understand the alternative and in this case, for a long-term solution, I would agree/prefer to break the compatibility (new XACML schema) and modify the Rule type definition directly.

One of the things I want to explore is flattening the structure by getting rid of PolicySet and letting Policy embed or reference other Policies, then we would only need AugmentedRule and AugmentedPolicy. Getting rid of Policy and letting PolicySet embed rules would amount to the same thing.

I agree completely with the idea of getting rid of PolicySet and letting Policy embed/reference others! :-) This would also remove/solve the issue #9 at the same time. So this change to the schema and the change for this issue (VariableDefinitions in Rule) could be done in the same new version of XACML.

@steven-legg
Copy link

The use case is for variables used in a Rule's Condition, Obligations or Advice (in order to simplify and/or optimize the Expressions) and for which the VariableDefinition - the value expression - depends on the Rule's Target. See the example of Policy down below.

Doesn't this following formulation give the same results using variable definitions at the policy level?

<Policy PolicyId="Organisation_specific_P"
              Version="1.0"
              RuleCombiningAlgId="urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:deny-unless-permit">
         <Target/>
         <VariableDefinition VariableId="action_id">
            <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-one-and-only">
               <AttributeDesignator Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action"
                                    AttributeId="urn:oasis:names:tc:xacml:1.0:action:action-id"
                                    DataType="http://www.w3.org/2001/XMLSchema#string"
                                    MustBePresent="true"/>
            </Apply>
         </VariableDefinition>

         <!-- Set the Variables to be used in the Condition - classification levels and other confidentiality category tags - according to ACME's policy. -->
         <VariableDefinition VariableId="ACME_resource_classif_level">
            <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only">
               <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                                  DataType="http://www.w3.org/2001/XMLSchema#integer"
                                  MustBePresent="true"
                                  Path="if (//*:Classification = 'CONFIDENTIAL') then 3 else if (//*:Classification = 'INTERNAL') then 2 else if (//*:Classification = 'PUBLIC') then 1 else 0"/>
            </Apply>
         </VariableDefinition>
         <VariableDefinition VariableId="ACME_subject_classif_level">
            <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only">
               <AttributeSelector Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
                                  DataType="http://www.w3.org/2001/XMLSchema#integer"
                                  MustBePresent="true"
                                  Path="if (//*:Classification = 'CONFIDENTIAL') then 3 else if (//*:Classification = 'INTERNAL') then 2 else if (//*:Classification = 'PUBLIC') then 1 else 0"/>
            </Apply>
         </VariableDefinition>
         <VariableDefinition VariableId="resource_cc_tags[Releasable To]">
            <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                               Path="//*:Category[@TagName='Releasable To']/*:GenericValue/text()"
                               DataType="http://www.w3.org/2001/XMLSchema#string"
                               MustBePresent="false"/>
         </VariableDefinition>
         <VariableDefinition VariableId="resource_cc_tags[Sensitive]">
            <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                               Path="//*:Category[@TagName='Sensitive']/*:GenericValue/text()"
                               DataType="http://www.w3.org/2001/XMLSchema#string"
                               MustBePresent="false"/>
         </VariableDefinition>

         <Rule RuleId="ACME_Company_R" Effect="Permit">
            <Description>
               Rule specific to ACME company's data protection policy.
               The ACME company is fictional, for illustration purposes only.
            </Description>
            <Target>
               <AnyOf>
                  <AllOf>
                     <Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                        <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">ACME</AttributeValue>
                        <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                                           Path="//*:PolicyIdentifier/text()"
                                           DataType="http://www.w3.org/2001/XMLSchema#string"
                                           MustBePresent="true"/>
                     </Match>
                  </AllOf>
               </AnyOf>
            </Target>

            <Condition>
               <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
                  <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:or">
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                           <VariableReference VariableId="action_id"/>
                           <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">READ</AttributeValue>
                        </Apply>
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal">
                           <VariableReference VariableId="ACME_subject_classif_level"/>
                           <VariableReference VariableId="ACME_resource_classif_level"/>
                        </Apply>
                     </Apply>
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                           <VariableReference VariableId="action_id"/>
                           <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">WRITE</AttributeValue>
                        </Apply>
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-less-than-or-equal">
                           <VariableReference VariableId="ACME_subject_classif_level"/>
                           <VariableReference VariableId="ACME_resource_classif_level"/>
                        </Apply>
                     </Apply>
                  </Apply>
                  <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:or">
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-equal">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-bag-size">
                           <VariableReference VariableId="resource_cc_tags[Releasable To]"/>
                        </Apply>
                        <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#integer">0</AttributeValue>
                     </Apply>
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-at-least-one-member-of">
                        <VariableReference VariableId="resource_cc_tags[Releasable To]"/>
                        <AttributeSelector Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
                                           Path="//*:Category[@TagName='Releasable To']/*:GenericValue/text()"
                                           DataType="http://www.w3.org/2001/XMLSchema#string"
                                           MustBePresent="false"/>
                     </Apply>
                  </Apply>
                  <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:or">
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-equal">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-bag-size">
                           <VariableReference VariableId="resource_cc_tags[Sensitive]"/>
                        </Apply>
                        <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#integer">0</AttributeValue>
                     </Apply>
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-subset">
                        <VariableReference VariableId="resource_cc_tags[Sensitive]"/>
                        <AttributeSelector Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
                                           Path="//*:Category[@TagName='Sensitive']/*:GenericValue/text()"
                                           DataType="http://www.w3.org/2001/XMLSchema#string"
                                           MustBePresent="false"/>
                     </Apply>
                  </Apply>
               </Apply>
            </Condition>
         </Rule>

         <!-- Set the Variables to be used in the Condition - classification levels and other confidentiality category tags - according to Foo Nation's policy. -->
         <VariableDefinition VariableId="FOO_resource_classif_level">
            <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only">
               <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                                  DataType="http://www.w3.org/2001/XMLSchema#integer"
                                  MustBePresent="true"
                                  Path="if (//*:Classification = 'FOO SECRET') then 4 else if (//*:Classification = 'FOO CONFIDENTIAL') then 3 else if (//*:Classification = 'FOO RESTRICTED') then 2 else if (//*:Classification = 'FOO UNCLASSIFIED') then 1 else 0"/>
            </Apply>
         </VariableDefinition>
         <VariableDefinition VariableId="FOO_subject_classif_level">
            <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only">
               <AttributeSelector Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
                                  DataType="http://www.w3.org/2001/XMLSchema#integer"
                                  MustBePresent="true"
                                  Path="if (//*:Classification = 'FOO SECRET') then 4 else if (//*:Classification = 'FOO CONFIDENTIAL') then 3 else if (//*:Classification = 'FOO RESTRICTED') then 2 else if (//*:Classification = 'FOO UNCLASSIFIED') then 1 else 0"/>
            </Apply>
         </VariableDefinition>
         <VariableDefinition VariableId="resource_cc_tags[Context]">
            <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                               Path="//*:Category[@TagName='Context']/*:GenericValue/text()"
                               DataType="http://www.w3.org/2001/XMLSchema#string"
                               MustBePresent="false"/>
         </VariableDefinition>
         <VariableDefinition VariableId="resource_cc_tags[Only]">
            <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                               Path="//*:Category[@TagName='Only']/*:GenericValue/text()"
                               DataType="http://www.w3.org/2001/XMLSchema#string"
                               MustBePresent="false"/>
         </VariableDefinition>
         <VariableDefinition VariableId="resource_cc_tags[Additional Sensitivity]">
            <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                               Path="//*:Category[@TagName='Additional Sensitivity']/*:GenericValue/text()"
                               DataType="http://www.w3.org/2001/XMLSchema#string"
                               MustBePresent="false"/>
         </VariableDefinition>

         <Rule RuleId="Foo_Nation_R" Effect="Permit">
            <Description>
               Rule specific to "Foo" nation's data protection policy. The nation "Foo" is one of ACME company's clients.
               The Foo nation is fictional, for illustration purposes only.
            </Description>
            <Target>
               <AnyOf>
                  <AllOf>
                     <Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                        <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">FOO</AttributeValue>
                        <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                                           Path="//*:PolicyIdentifier/text()"
                                           DataType="http://www.w3.org/2001/XMLSchema#string"
                                           MustBePresent="true"/>
                     </Match>
                  </AllOf>
               </AnyOf>
            </Target>

            <Condition>
               <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
                  <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:or">
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                           <VariableReference VariableId="action_id"/>
                           <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">READ</AttributeValue>
                        </Apply>
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal">
                           <VariableReference VariableId="FOO_subject_classif_level"/>
                           <VariableReference VariableId="FOO_resource_classif_level"/>
                        </Apply>
                     </Apply>
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                           <VariableReference VariableId="action_id"/>
                           <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">WRITE</AttributeValue>
                        </Apply>
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-less-than-or-equal">
                           <VariableReference VariableId="FOO_subject_classif_level"/>
                           <VariableReference VariableId="FOO_resource_classif_level"/>
                        </Apply>
                     </Apply>
                  </Apply>
                  <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:or">
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-equal">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-bag-size">
                           <VariableReference VariableId="resource_cc_tags[Context]"/>
                        </Apply>
                        <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#integer">0</AttributeValue>
                     </Apply>
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-subset">
                        <VariableReference VariableId="resource_cc_tags[Context]"/>
                        <AttributeSelector Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
                                           Path="//*:Category[@TagName='Context']/*:GenericValue/text()"
                                           DataType="http://www.w3.org/2001/XMLSchema#string"
                                           MustBePresent="false"/>
                     </Apply>
                  </Apply>
                  <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:or">
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-equal">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-bag-size">
                           <VariableReference VariableId="resource_cc_tags[Only]"/>
                        </Apply>
                        <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#integer">0</AttributeValue>
                     </Apply>
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-subset">
                        <VariableReference VariableId="resource_cc_tags[Only]"/>
                        <AttributeSelector Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
                                           Path="//*:Category[@TagName='Only']/*:GenericValue/text()"
                                           DataType="http://www.w3.org/2001/XMLSchema#string"
                                           MustBePresent="false"/>
                     </Apply>
                  </Apply>
                  <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:or">
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-equal">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-bag-size">
                           <VariableReference VariableId="resource_cc_tags[Additional Sensitivity]"/>
                        </Apply>
                        <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#integer">0</AttributeValue>
                     </Apply>
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-at-least-one-member-of">
                        <VariableReference VariableId="resource_cc_tags[Additional Sensitivity]"/>
                        <AttributeSelector Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
                                           Path="//*:Category[@TagName='Additional Sensitivity']/*:GenericValue/text()"
                                           DataType="http://www.w3.org/2001/XMLSchema#string"
                                           MustBePresent="false"/>
                     </Apply>
                  </Apply>

                  <!--
            etc.
            For brevity, Apply Expressions for other confidentiality categories are omitted here.
            -->

               </Apply>
            </Condition>
         </Rule>

         <!-- Set the Variables to be used in the Condition - classification levels - according to EU policy. -->
         <VariableDefinition VariableId="EU_resource_classif_level">
            <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only">
               <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                                  DataType="http://www.w3.org/2001/XMLSchema#integer"
                                  MustBePresent="true"
                                  Path="if (//*:Classification = 'EU SECRET') then 4 else if (//*:Classification = 'EU CONFIDENTIAL') then 3 else if (//*:Classification = 'EU RESTRICTED') then 2 else if (//*:Classification = 'UNCLASSIFIED') then 1 else 0"/>
            </Apply>
         </VariableDefinition>
         <VariableDefinition VariableId="EU_subject_classif_level">
            <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-one-and-only">
               <AttributeSelector Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
                                  DataType="http://www.w3.org/2001/XMLSchema#integer"
                                  MustBePresent="true"
                                  Path="if (//*:Classification = 'EU SECRET') then 4 else if (//*:Classification = 'EU CONFIDENTIAL') then 3 else if (//*:Classification = 'EU RESTRICTED') then 2 else if (//*:Classification = 'UNCLASSIFIED') then 1 else 0"/>
            </Apply>
         </VariableDefinition>

         <Rule RuleId="EU_R" Effect="Permit">
            <Description>
               Rule specific to EU data protection policy, in case ACME Company is based in the EU.
               This example is for illustration purposes only, i.e. not official in any way.
            </Description>
            <Target>
               <AnyOf>
                  <AllOf>
                     <Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                        <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">EU</AttributeValue>
                        <AttributeSelector Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
                                           Path="//*:PolicyIdentifier/text()"
                                           DataType="http://www.w3.org/2001/XMLSchema#string"
                                           MustBePresent="true"/>
                     </Match>
                  </AllOf>
               </AnyOf>
            </Target>

            <Condition>
               <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
                  <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:or">
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                           <VariableReference VariableId="action_id"/>
                           <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">READ</AttributeValue>
                        </Apply>
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-greater-than-or-equal">
                           <VariableReference VariableId="EU_subject_classif_level"/>
                           <VariableReference VariableId="EU_resource_classif_level"/>
                        </Apply>
                     </Apply>
                     <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
                           <VariableReference VariableId="action_id"/>
                           <AttributeValue DataType="http://www.w3.org/2001/XMLSchema#string">WRITE</AttributeValue>
                        </Apply>
                        <Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-less-than-or-equal">
                           <VariableReference VariableId="EU_subject_classif_level"/>
                           <VariableReference VariableId="EU_resource_classif_level"/>
                        </Apply>
                     </Apply>
                  </Apply>
               </Apply>
            </Condition>
</Rule>

All I've done is move the variable definitions before the rules and prefixed the identifiers of the ones that are overloaded and rule-specific.

As far as I can see, the only dependency a variable definition can have on a target is whether it gets evaluated. It evaluates to the same value regardless of where the definition is put. If the goal is to avoid evaluating variable definitions that aren't needed then an extension isn't required for that. I only evaluate a variable definition on the first variable reference to it.

@cdanger
Copy link
Author

cdanger commented Nov 30, 2023

If the goal is to avoid evaluating variable definitions that aren't needed then an extension isn't required for that. I only evaluate a variable definition on the first variable reference to it.

Yes, I understand you have a solution that works for you, but such behavior (evaluating only on the first reference) is not mandatory per XACML standard, it may be different for another implementation than yours (eager vs lazy evaluation). So if we take the point of view of the average policy writer, who wants to write policies in the optimal way regardless of the PDP implementation, and, more importantly, who wants to follow the best practice Minimize the scope of variables, as he/she should, the possibility to declare variables (VariableDefinitions) in the smallest block possible (where they are used only) would be very much appreciated (e.g. in a Rule for variables used only in that Rule). I think it is a noticeable enhancement towards that goal if we can offer that possibility to policy writers.

Quote from the recommendation:

Variables and functions should be declared in the minimum scope from which all references to the identifier are still possible. When a larger scope than necessary is used, code becomes less readable, harder to maintain, and more likely to reference unintended variables

@steven-legg
Copy link

So if we take the point of view of the average policy writer, who wants to write policies in the optimal way regardless of the PDP implementation

I take the point of view that policy writers shouldn't have to be concerned with what is or isn't an optimal way to write policies for different PDPs. Even with this change, lazy evaluation is still better because evaluation of variable definitions before the condition in a rule can still be wasted effort. In your example, if the action isn't READ or WRITE then the evaluations of the variable definitions aren't needed. From the performance point of view I see the justification for this change as providing a way for implementations that have chosen a sub-optimal strategy for evaluating variables to be a bit less sub-optimal when there is a better performing strategy available that isn't hard to implement and requires no change to the standard. We should encourage PDP implementors to do things well so that policy writers don't have to make allowances.

On the question of minimizing scope, given how my PAP abstracts the handling of variable definitions my policy writers wouldn't see a difference with this change. Scope is not something they need to be concerned with, so minimizing it is not relevant to them. The PAP takes care of it.

If we are talking about this change on its own I wouldn't consider it worthwhile since it involves extra coding for me for no benefit. But I'll tolerate it if it is bundled with other things that I would find useful.

@cdanger
Copy link
Author

cdanger commented Jan 4, 2024

OK on standby for now then.

@cdanger cdanger changed the title Feature Request - Add VariableDefinitions as optional elements in Rule (like in Policy) Add VariableDefinitions as optional elements in Rule (like in Policy) Mar 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants