You can easily do that in XACML (and ALFA - the more lightweight syntax of XACML). First of all, you stated that:
Each section would permit or deny
To do so, you will use a Policy for each section that uses the deny-unless-permit
combining algorithm. This means that either the policy will grant access if the conditions are met or it will deny access. You might remember that by default, if conditions are not met, the usual decision is NotApplicable
. Using deny-unless-permit
will prevent that.
and any deny will fail the overall policy
Once you have written each policy using deny-unless-permit
, you will combine them all into a parent policy set which will use a deny-overrides
combining algorithm. This means that if there is any deny decision, then that decision will trump all other decisions.
This gives us the following structure:
ALFA
namespace com.axiomatics{
/**
* Resource data labeling to provide access control to data
*/
policyset dataAccess{
apply denyOverrides
/**
* First check
*/
policy firstCheck{
apply denyUnlessPermit
/**
* Allow if clearance is sufficient
*/
rule clearanceCheck{
permit
condition com.acme.user.clearance > com.acme.record.classification
}
rule otherCheck{
// Fill in your checks here
permit
}
}
/**
* Second check...
*/
policy secondCheck{
apply denyUnlessPermit
}
}
}
Equivalent in XACML
<?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:PolicySet
PolicyCombiningAlgId="urn:oasis:names:tc:xacml:3.0:policy-combining-algorithm:deny-overrides"
PolicySetId="http://axiomatics.com/alfa/identifier/com.axiomatics.dataAccess"
Version="1.0"
xmlns:xacml3="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17">
<xacml3:Description>Resource data labeling to provide access control to
data</xacml3:Description>
<xacml3:PolicySetDefaults>
<xacml3:XPathVersion>http://www.w3.org/TR/1999/REC-xpath-19991116
</xacml3:XPathVersion>
</xacml3:PolicySetDefaults>
<xacml3:Target />
<xacml3:Policy
PolicyId="http://axiomatics.com/alfa/identifier/com.axiomatics.dataAccess.firstCheck"
RuleCombiningAlgId="urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:deny-unless-permit"
Version="1.0">
<xacml3:Description>First check</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="com.axiomatics.dataAccess.firstCheck.clearanceCheck">
<xacml3:Description>Allow if clearance is sufficient
</xacml3:Description>
<xacml3:Target />
<xacml3:Condition>
<xacml3:Apply
FunctionId="urn:oasis:names:tc:xacml:3.0:function:any-of-any">
<xacml3:Function
FunctionId="urn:oasis:names:tc:xacml:1.0:function:integer-greater-than" />
<xacml3:AttributeDesignator
AttributeId="com.acme.user.clearance"
Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
DataType="http://www.w3.org/2001/XMLSchema#integer"
MustBePresent="false" />
<xacml3:AttributeDesignator
AttributeId="com.acme.record.classification"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
DataType="http://www.w3.org/2001/XMLSchema#integer"
MustBePresent="false" />
</xacml3:Apply>
</xacml3:Condition>
</xacml3:Rule>
<xacml3:Rule Effect="Permit"
RuleId="com.axiomatics.dataAccess.firstCheck.otherCheck">
<xacml3:Description />
<xacml3:Target />
</xacml3:Rule>
</xacml3:Policy>
<xacml3:Policy
PolicyId="http://axiomatics.com/alfa/identifier/com.axiomatics.dataAccess.secondCheck"
RuleCombiningAlgId="urn:oasis:names:tc:xacml:3.0:rule-combining-algorithm:deny-unless-permit"
Version="1.0">
<xacml3:Description>Second check...</xacml3:Description>
<xacml3:PolicyDefaults>
<xacml3:XPathVersion>http://www.w3.org/TR/1999/REC-xpath-19991116
</xacml3:XPathVersion>
</xacml3:PolicyDefaults>
<xacml3:Target />
</xacml3:Policy>
</xacml3:PolicySet>
Other Checks
In addition to your policy structure, you mention that you would to control access based on attributes (e.g. a user can view a document they own) and also based on explicit access control (a user can view a document if they are on the list for that document). You can absolutely implement discretionary access control (DAC) in XACML in addition to attribute-based access. Here is an example:
/**
* Second check...
*/
policy secondCheck{
target clause com.acme.action.actionId == "view" and com.acme.object.objectType == "document"
apply denyUnlessPermit
/**
* Users can view documents they own
*/
rule owner{
permit
condition com.acme.record.owner==user.userId
}
/**
* Users in the whitelist can view the document
*/
rule dac{
permit
condition stringAtLeastOneMemberOf(user.userId, com.acme.record.whitelist)
}
}