I've read through the 3.0 specs and had a question here:
I found PolicySet and Policy share many similarities like the combining algorithms, etc. And to accommodate more levels, PolicySet also can be self-containable. If so, why not merge PolicySet and Policy into a single concept named Policy and make Policy contain other Policies and Rules?
Update:
Speaking of Rule, actually Rule doesn't differ with Policy much either, except that Rule has Condition and Effect and doesn't have a combining algorithm. What I am thinking of now is merging the three conceptions: PolicySet, Policy, Rule into a single new Policy. This Policy is self-containable and can has its Condition and Effect. If its combining algorithm returns Intermediate, then use its own Effect. The whole policy is not applicable if its own Condition fails to meet the request. I personally think this one-concept model is more concise and clear than the PolicySet, Policy and Rule.
For example, for a four-level policy (if there's a demand for a four-level policy for a big enterprise), XACML will represent like:
PolicySet -> PolicySet(s) -> Policy(s) -> Rule(s)
My modification would be:
Policy -> Policy(s) -> Policy(s) -> Policy(s)
Compared to the XACML's two-level PolicySets and a level Policy and Rule, I think a straightforward four-level Policies would be clearer?
The fact both exist is a quirk of the language. You could imagine a language with a leaf element (the rule) and a branch (the policy).
Both Policy and PolicySet are very similar. When modeling in XACML you can assimilate them.
You'd have a policy that can contain other policies XOR rules but not both at the same time
Following the OP's edit, here is a bit more context.
XACML introduces 3 structural elements:
As the OP states, PolicySet can contain Policy and PolicySet thus allowing for an overall tree that is as deep as the author wants it to be (PS --> PS --> PS ... --> P --> R).
All three elements (PS, P, R) can contain:
role=='manager' OR role=='editor'
.Because PolicySet and Policy elements can contain children, they need a mechanism to resolve conflicts between children. That mechanism is called a combining algorithm. Therefore both PolicySet elements and Policy elements have a combining algorithm property. Since PolicySets contain other PolicySets and/or Policy elements, the combining algorithm in a PolicySet is called a policy combining algorithm. Since Policy elements contain Rules only, the combining algorithm is called a rule combining algorithm.
Another quirk of XACML is that the list of combining algorithms for policies is nearly almost the same as for rules. The notable differences are:
Here is the list in the ALFA notation (ALFA is a pseudo-language developed by Axiomatics to simplify XACML policy authoring):
namespace System {
ruleCombinator denyOverrides = "urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:deny-overrides"
ruleCombinator permitOverrides = "urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:permit-overrides"
ruleCombinator firstApplicable = "urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable"
ruleCombinator orderedDenyOverrides = "urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:ordered-deny-overrides"
ruleCombinator orderedPermitOverrides = "urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:ordered-permit-overrides"
ruleCombinator denyUnlessPermit = "urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:deny-unless-permit"
ruleCombinator permitUnlessDeny = "urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:permit-unless-deny"
policyCombinator denyOverrides = "urn:oasis:names:tc:xacml:3.0:policy-combining-algorithm:deny-overrides"
policyCombinator permitOverrides = "urn:oasis:names:tc:xacml:3.0:policy-combining-algorithm:permit-overrides"
policyCombinator firstApplicable = "urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:first-applicable"
policyCombinator onlyOneApplicable = "urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:only-one-applicable"
policyCombinator orderedDenyOverrides = "urn:oasis:names:tc:xacml:3.0:policy-combining-algorithm:ordered-deny-overrides"
policyCombinator orderedPermitOverrides = "urn:oasis:names:tc:xacml:3.0:policy-combining-algorithm:ordered-permit-overrides"
policyCombinator denyUnlessPermit = "urn:oasis:names:tc:xacml:3.0:policy-combining-algorithm:deny-unless-permit"
policyCombinator permitUnlessDeny = "urn:oasis:names:tc:xacml:3.0:policy-combining-algorithm:permit-unless-deny"
policyCombinator onPermitApplySecond = "urn:oasis:names:tc:xacml:3.0:policy-combining-algorithm:on-permit-apply-second"
}
As previously stated, Target elements can exist in any of PolicySet, Policy, and Rule. A Target has a set structure of AND/OR/AND elements to combine together attribute matches i.e. the comparison of a given attribute to a given value. XACML provides a long list of functions that can be used.
In a target only functions that take 2 atomic values and return a boolean can be used e.g. == (or urn:oasis:names:tc:xacml:1.0:function:string-equal). Other functions e.g. sum (urn:oasis:names:tc:xacml:1.0:function:integer-add) cannot be used.
In particular, there is one really useful thing Target elements cannot do: compare two attributes together i.e. establish a relationship. Imagine for instance you want to write a Policy that states:
Doctors can view the medical record of a patient they are assigned to.
Or in other words, Permit if userId == assignedDoctorId
.
This is where Condition elements kick in. A Condition is an expression that can use any function available in XACML. The overall outcome of the Condition must be a boolean but now you can do things like sum(age, limit)>5
or userId == assignedDoctorId
.
And here comes another quirk: Condition elements can only be used inside a Rule element. So, if you want to express a relationship in XACML, you will need to have at least one Rule. And since a Rule element cannot live on its own. You will have to have at least one Policy element.
So the smallest possible XACML policy is (using ALFA):
namespace example{
policy policyExample{
apply denyOverrides
rule allowAll{
permit
}
}
}
And the resulting XACML XML code is:
<?xml version="1.0" encoding="UTF-8"?>
<!--This file was generated by the ALFA Plugin for Eclipse from Axiomatics AB (http://www.axiomatics.com).
Any modification to this file will be lost upon recompilation of the source ALFA file-->
<xacml3:Policy xmlns:xacml3="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
PolicyId="http://axiomatics.com/alfa/identifier/example.policyExample"
RuleCombiningAlgId="urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:deny-overrides"
Version="1.0">
<xacml3:Description />
<xacml3:PolicyDefaults>
<xacml3:XPathVersion>http://www.w3.org/TR/1999/REC-xpath-19991116</xacml3:XPathVersion>
</xacml3:PolicyDefaults>
<xacml3:Target />
<xacml3:Rule
Effect="Permit"
RuleId="http://axiomatics.com/alfa/identifier/example.policyExample.allowAll">
<xacml3:Description />
<xacml3:Target />
</xacml3:Rule>
</xacml3:Policy>