Reputation: 4286
I'm trying to decide what authorization technology/methodology to do for a project and XACML has a lot of interesting features. One thing I can't wrap my head around though is the need for combining algorithms. Are there complex scenarios where they are needed?
Say that, instead, access to a resource type (or whatever) is Permit or Deny per default. A rule defines a condition for either a permit or deny (never both).
If there's any deny it's denied (immediately). If it's "deny by default" and there's no permit, it's also denied. Rules could have priority and a permit/deny on any higher level would override those below it.
Rules would be more piecemeal Permit/Deny rather than one big rule with advanced combining algorithms.
Am I missing some major scenarios (probably) that wouldn't be covered by such an approach? Maybe a hard question to answer :) Hoping someone with a lot of XACML experience and/or access control can shed some light on the design thinking and their experience with such policies.
Thanks in advance!
EDIT: (as reply to George because too long)
Super thanks for answering David! Read a lot of your posts and articles, good stuff.
I hear what you're saying and there's a lot of intricacies (reading the emailing list on some of the design decisions and the evaluation logic, whew, hairy stuff :) But it almost seems like the hierarchical structure is what adds a lot of complexity, and I don't quite see why it's needed.
According to the logic I wrote, I could just have these two rules (if I understand the XACML correctly)
PERMIT: unit = "bu1"
DENY: unit = "bu1" AND apiPath == "/finance" AND objectType== "trade" AND trade.amount > user.allowedAmount
It seems easier to individually tailor rules than them being part of one big rule, and does one really need to think of them as one rule if you write them like this? I guess you'd have a general mindset of permitting the general cases and denying the exceptions.
So second sample, this is why I think you actually need "priority levels" to resolve some things.
Priority 1:
PERMIT: megaemergency = true
Priority 2:
PERMIT: emergency = true AND u.approvalLimit >= c.amount.
Priority 3:
PERMIT: u.region = c.region AND u.approvalLimit >= c.amount.
Since it short circuits on PERMIT or DENY on any "priority level", and they're evaluated in order, wouldn't the result be the same? And the person who authors the lower priority rules wouldn't really need to know about the rules with higher priority.
Last example would be:
PERMIT: u.citizenship == "U.S" AND u.enteringFrom == "Canada"
DENY: u.citizenship != "U.S" AND u.enteringFrom == "Canada"
(I mean there would have to be other rules too :)
Since DENY overrides Permit, and any DENY denies you're set.
I guess I'm having trouble seeing the edge-cases that can't be handled by such an approach... Maybe I'm having a head fart :)
Sorry again, the scope of the question is a bit wide.
Upvotes: 2
Views: 208
Reputation: 13832
Deny by default is definitely a good approach but sometimes it makes sense to have more flexibility and define and how rules (or policies) can be combined.
Here is what the standard says:
The complete policy applicable to a particular decision request may be composed of a number of individual rules or policies. For instance, in a personal privacy application, the owner of the personal information may define certain aspects of disclosure policy, whereas the enterprise that is the custodian of the information may define certain other aspects. In order to render an authorization decision, it must be possible to combine the two separate policies to form the single policy applicable to the request. Source
Permit
, Deny
, NotApplicable
, and Indeterminate
.A common pattern when writing XACML policies is to define a hierarchical structure of policies. You do that because you want your policies to be manageable. So, let's imagine you are Acme Inc. and you have 5 business units and you have 5 APIs which in turn have 5 methods.
Your policy might look like the following stub (in alfa):
policyset acme{
apply firstApplicable
policyset bu1{
target clause unit == "bu1"
apply firstApplicable
policyset financeApi{
target clause apiPath == "/finance"
apply firstApplicable
policy buyTrade{
target clause objectType == "trade"
apply firstApplicable
rule denyIfAmountTooLarge{
deny
condition trade.amount > user.allowedAmount
on deny{
obligation notify {
message = "You cannot approve this transaction because..."
}
}
}
}
}
}
}
If it was deny by default and deny first, then I wouldn't be able to have multiple policies in parallel (for BU1, BU2...). I wouldn't be able to nest policies as easily. Also there could be a chance I'm denying or permitting access by mistake. I need to control at each level what the outcome might be and what to do if we get NotApplicable
or Indeterminate
back.
One of the main drawbacks of access control lists or NAC-style rules is the fact that you potentially end up with too many rules and it's hard to understand which rules describe which access. In NAC, for instance, how do you know whether UDP on a given port is allowed or disallowed. From what IP range?
More advanced policy languages like XACML and ALFA give you the ability to create a tree of policies. This means you can organize your policies in a tree-like structure that:
Imagine you are an insurance company processing claims. Your baseline policy is: a claims agent can only view claims in their region and can only approve payouts up to their limit. So in your mind you have Permit if u.region = c.region and u.approvalLimit >= c.amount.
But what if this is an emergency, you want all your employees to service all regions. So now you need a policy that can override the region restriction. You cannot really do that in a flat list, deny-wins structure. This is where XACML/ALFA come in handy because the syntax & structure is rich enough to address these scenarios.
Here are some more that make sense
Sometimes, you don't want to deny as soon as you can. You want to tell the end user all the reasons why access is denied. For instance, a claims processor cannot approve a claim because (a) the amount is too much, (b) the region is not the same as the employee's region and (c) there is a conflict of interest. If you told the user piecemeal information, you'd force your user to retry approving 3 times and getting denied 3 times.
This is the opposite of the previous statement and the most common pattern: you want to reveal as little as possible and deny as soon as you can. Your model could work here.
This is also known as the Berg pattern. Instead of saying:
You could say allow if - region is right - amount is under limit
In that case, you want to collect all the Permit decisions and then flip them if need be. This requires permit-overrides and deny-unless-permit. You wouldn't be able to do that with just a Deny strategy.
Be careful with deny policies. What if you write a policy that says:
In XACML, if for some reason the value for citizenship is not present, then access won't be denied. We don't know whether the user is American or not American. So you have to think about value presence too.
Axiomatics has a great write-up on combining algorithms. I suggest you check it out.
Upvotes: 3