My company is looking to implement a centralized security service, and it seems like a popular standard for that is XACML. I have a complex authorization scenario and I've been having trouble figuring out how it could be defined using attributes for XACML policies.
The system I'm working on has several pieces relevant to this authentication scenario:
In the case where a user wants to view the recipe for a particular item, any of the following must be true:
With those rules, it seems like the attributes needed to determine if a user can view a recipe include:
Questions:
(disclaimer - I work for Axiomatics, the leading implementation of XACML and ABAC)
Great question. I've actually put together an authorization policy lifecycle which walks users through the process of gathering requirements, identifying attributes, and implementing policies.
In your case, let's walk through your requirements
Any of the following must be true:
- The user must be the owner of the recipe (the person who wrote it).
- The user must be a team member on the project where the recipe was created. (either directly or via group membership)
- The user must be a member of a group manufacturing the recipe. (They need to see the recipe to manufacture it.)
- The user must be a member of a group that has manufactured the recipe within the past two weeks. (i.e., after completing a request to manufacture the recipe, they can continue to view the recipe for two weeks to correct any problems.)
- The user must be an administrator.
I like to rework requirements as subject - verb - object e.g. A user can view a recipe... Based on this model your original requirements can be reworded as the following:
You can break down attributes into different categories (or grammatical functions). XACML uses categories itself so this is a natural step towards implementing using XACML (or ALFA).
In this category, by the looks of it, you only have:
The next step is to implement your policies. You can use ALFA (Abbreviated Language for Authorization). Axiomatics has an Eclipse plugin that translates ALFA into XACML 3.0.
Let's create a policy set that handles recipes. That policy set will contain a policy that handles the action view. That policy in turn will contain rules that address each requirement.
policyset recipe{
target clause objectType == "recipe"
apply firstApplicable
/**
* View recipes
*/
policy viewRecipe{
target clause actionId == "view"
apply firstApplicable
/**
* Administrators can view all recipes
*/
rule administrator{
target clause user.role == "administrator"
permit
}
/**
* Recipe owners can view their own recipes
*/
rule owner{
permit
condition user.userId == recipe.owner
}
/**
* Users can view recipes in their project
*/
rule sameProject{
permit
condition user.assignedProject == recipe.assignedProject
}
/**
* Users can view recipes in their project
*/
rule sameGroup{
target clause recipe.stage == "manufacturing"
permit
condition user.assignedGroup == recipe.assignedGroup
}
/**
* Users can view recipes in their project
*/
rule sameGroupManufactured{
target clause recipe.stage == "manufacturing"
permit
condition user.assignedGroup == recipe.assignedGroup && currentDate<=dateTimeAddDayTimeDuration(dateTimeOneAndOnly(recipe.manufacturedDate),"P14D":dayTimeDuration)
}
}
}
How would a PIP gather this information? Directly from a database? Via service calls to the system that stores this information?
A PIP is just an abstract notion of an external attribute source. It can be anything. Different implementations will have different PIP connectors. For instance Axiomatics Policy Server provides connectors to SQL, LDAP, and REST services. This covers most of a client's needs.
You compare both technologies but they are somehow a little different. OAuth 2.0 focuses first and foremost on authentication. It came about to defeat the password anti-pattern. Then there was a need to define permissions or, as they call them in OAuth, scopes. However those scopes are only punctual permissions. You still rely on the target application to publish a set of valid scopes and you still cannot do fine-grained access control. My colleague wrote a three-part blog on the topic, the first part of which you can read here.
I hope this helps. Feel free to ask follow-up questions or tweet to me.
<?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 xmlns:xacml3="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
PolicySetId="http://axiomatics.com/alfa/identifier/so.recipe"
PolicyCombiningAlgId="urn:oasis:names:tc:xacml:1.0:policy-combining-algorithm:first-applicable"
Version="1.0">
<xacml3:Description>Control access to recipes</xacml3:Description>
<xacml3:PolicySetDefaults>
<xacml3:XPathVersion>http://www.w3.org/TR/1999/REC-xpath-19991116</xacml3:XPathVersion>
</xacml3:PolicySetDefaults>
<xacml3:Target>
<xacml3:AnyOf>
<xacml3:AllOf>
<xacml3:Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<xacml3:AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">recipe</xacml3:AttributeValue>
<xacml3:AttributeDesignator
AttributeId="so.objectType"
DataType="http://www.w3.org/2001/XMLSchema#string"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
MustBePresent="false"
/>
</xacml3:Match>
</xacml3:AllOf>
</xacml3:AnyOf>
</xacml3:Target>
<xacml3:Policy xmlns:xacml3="urn:oasis:names:tc:xacml:3.0:core:schema:wd-17"
PolicyId="http://axiomatics.com/alfa/identifier/so.recipe.viewRecipe"
RuleCombiningAlgId="urn:oasis:names:tc:xacml:1.0:rule-combining-algorithm:first-applicable"
Version="1.0">
<xacml3:Description>View recipes</xacml3:Description>
<xacml3:PolicyDefaults>
<xacml3:XPathVersion>http://www.w3.org/TR/1999/REC-xpath-19991116</xacml3:XPathVersion>
</xacml3:PolicyDefaults>
<xacml3:Target>
<xacml3:AnyOf>
<xacml3:AllOf>
<xacml3:Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<xacml3:AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">view</xacml3:AttributeValue>
<xacml3:AttributeDesignator
AttributeId="so.actionId"
DataType="http://www.w3.org/2001/XMLSchema#string"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:action"
MustBePresent="false"
/>
</xacml3:Match>
</xacml3:AllOf>
</xacml3:AnyOf>
</xacml3:Target>
<xacml3:Rule
Effect="Permit"
RuleId="http://axiomatics.com/alfa/identifier/so.recipe.viewRecipe.administrator">
<xacml3:Description>Administrators can view all recipes</xacml3:Description>
<xacml3:Target>
<xacml3:AnyOf>
<xacml3:AllOf>
<xacml3:Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<xacml3:AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">administrator</xacml3:AttributeValue>
<xacml3:AttributeDesignator
AttributeId="so.user.role"
DataType="http://www.w3.org/2001/XMLSchema#string"
Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
MustBePresent="false"
/>
</xacml3:Match>
</xacml3:AllOf>
</xacml3:AnyOf>
</xacml3:Target>
</xacml3:Rule>
<xacml3:Rule
Effect="Permit"
RuleId="http://axiomatics.com/alfa/identifier/so.recipe.viewRecipe.owner">
<xacml3:Description>Recipe owners can view their own recipes</xacml3:Description>
<xacml3:Target />
<xacml3:Condition>
<xacml3:Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:any-of-any">
<xacml3:Function FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal"/>
<xacml3:AttributeDesignator
AttributeId="so.user.userId"
DataType="http://www.w3.org/2001/XMLSchema#string"
Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
MustBePresent="false"
/>
<xacml3:AttributeDesignator
AttributeId="so.recipe.owner"
DataType="http://www.w3.org/2001/XMLSchema#string"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
MustBePresent="false"
/>
</xacml3:Apply>
</xacml3:Condition>
</xacml3:Rule>
<xacml3:Rule
Effect="Permit"
RuleId="http://axiomatics.com/alfa/identifier/so.recipe.viewRecipe.sameProject">
<xacml3:Description>Users can view recipes in their project</xacml3:Description>
<xacml3:Target />
<xacml3:Condition>
<xacml3:Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:any-of-any">
<xacml3:Function FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal"/>
<xacml3:AttributeDesignator
AttributeId="so.user.assignedProject"
DataType="http://www.w3.org/2001/XMLSchema#string"
Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
MustBePresent="false"
/>
<xacml3:AttributeDesignator
AttributeId="so.recipe.assignedProject"
DataType="http://www.w3.org/2001/XMLSchema#string"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
MustBePresent="false"
/>
</xacml3:Apply>
</xacml3:Condition>
</xacml3:Rule>
<xacml3:Rule
Effect="Permit"
RuleId="http://axiomatics.com/alfa/identifier/so.recipe.viewRecipe.sameGroup">
<xacml3:Description>Users can view recipes in their project</xacml3:Description>
<xacml3:Target>
<xacml3:AnyOf>
<xacml3:AllOf>
<xacml3:Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<xacml3:AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">manufacturing</xacml3:AttributeValue>
<xacml3:AttributeDesignator
AttributeId="so.recipe.stage"
DataType="http://www.w3.org/2001/XMLSchema#string"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
MustBePresent="false"
/>
</xacml3:Match>
</xacml3:AllOf>
</xacml3:AnyOf>
</xacml3:Target>
<xacml3:Condition>
<xacml3:Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:any-of-any">
<xacml3:Function FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal"/>
<xacml3:AttributeDesignator
AttributeId="so.user.assignedGroup"
DataType="http://www.w3.org/2001/XMLSchema#string"
Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
MustBePresent="false"
/>
<xacml3:AttributeDesignator
AttributeId="so.recipe.assignedGroup"
DataType="http://www.w3.org/2001/XMLSchema#string"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
MustBePresent="false"
/>
</xacml3:Apply>
</xacml3:Condition>
</xacml3:Rule>
<xacml3:Rule
Effect="Permit"
RuleId="http://axiomatics.com/alfa/identifier/so.recipe.viewRecipe.sameGroupManufactured">
<xacml3:Description>Users can view recipes in their project</xacml3:Description>
<xacml3:Target>
<xacml3:AnyOf>
<xacml3:AllOf>
<xacml3:Match MatchId="urn:oasis:names:tc:xacml:1.0:function:string-equal">
<xacml3:AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#string">manufacturing</xacml3:AttributeValue>
<xacml3:AttributeDesignator
AttributeId="so.recipe.stage"
DataType="http://www.w3.org/2001/XMLSchema#string"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
MustBePresent="false"
/>
</xacml3:Match>
</xacml3:AllOf>
</xacml3:AnyOf>
</xacml3:Target>
<xacml3:Condition>
<xacml3:Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:and">
<xacml3:Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:any-of-any">
<xacml3:Function FunctionId="urn:oasis:names:tc:xacml:1.0:function:string-equal"/>
<xacml3:AttributeDesignator
AttributeId="so.user.assignedGroup"
DataType="http://www.w3.org/2001/XMLSchema#string"
Category="urn:oasis:names:tc:xacml:1.0:subject-category:access-subject"
MustBePresent="false"
/>
<xacml3:AttributeDesignator
AttributeId="so.recipe.assignedGroup"
DataType="http://www.w3.org/2001/XMLSchema#string"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
MustBePresent="false"
/>
</xacml3:Apply>
<xacml3:Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:any-of">
<xacml3:Function FunctionId="urn:oasis:names:tc:xacml:1.0:function:dateTime-greater-than-or-equal"/>
<xacml3:Apply FunctionId="urn:oasis:names:tc:xacml:3.0:function:dateTime-add-dayTimeDuration" >
<xacml3:Apply FunctionId="urn:oasis:names:tc:xacml:1.0:function:dateTime-one-and-only" >
<xacml3:AttributeDesignator
AttributeId="so.recipe.manufacturedDate"
DataType="http://www.w3.org/2001/XMLSchema#dateTime"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:resource"
MustBePresent="false"
/>
</xacml3:Apply>
<xacml3:AttributeValue
DataType="http://www.w3.org/2001/XMLSchema#dayTimeDuration">P14D</xacml3:AttributeValue>
</xacml3:Apply>
<xacml3:AttributeDesignator
AttributeId="currentDate"
DataType="http://www.w3.org/2001/XMLSchema#dateTime"
Category="urn:oasis:names:tc:xacml:3.0:attribute-category:environment"
MustBePresent="false"
/>
</xacml3:Apply>
</xacml3:Apply>
</xacml3:Condition>
</xacml3:Rule>
</xacml3:Policy>
</xacml3:PolicySet>