I have a fairly complicated ACL set which I need to optimize the evaluation of. To do this I need to make decisions based on the requested access level, which currently isn't possible (as far as I know that is). E.g, most of my ACLs are concerned with whether the entries and attributes should be read or writable or not, and I would like to quickly grant search access when that is all that is requested.
One possibility I have considered is to add a new optional <requested access> field between the existing <who> and the <access> clauses, but I'm not very happy with that solution as it could easily be mixed with the existing <access>.
So far my preferred solution is to add two new ACL controls, which I currently think of as "sufficient" and "requested".
The "sufficient" control should act like "stop" (i.e grant access) if the effective <access> is sufficient for the requested access level, "continue" otherwise.
The "requested" control should act like "continue" if the effective <access> matches what is requested, "break" otherwise.
I initially thought that "break" should be the non-match action in both controls, but I think "continue" is the best for "sufficient" as that allows further decisions to be made in the same ACL without repeating the <to> part in a following ACL. At the cost of repeating the <who> part in a new condition in the same ACL if "break" was really needed.. I.e, both choices have their ups and downs, and I can live with both.
I also though that "stop" should be the non-match case for "requested" to make the controls more symmetric. But that removes the ability to make further decisions in the succeeding rules, which I find highly unsatisfactory.
These controls would allow access rules like the following to quickly grant search access if that is all that is requested, while keep on processing for other access types:
access to <what> by <who> =s sufficient by * break
An access rule where the <who> clauses are only evaluated when write access is requested could be written like:
access to <what> by * =w requested by <who> =w
Comments? It should be fairly easy to implement these controls, and I'll volunteer to do it if they are acceptable.
-- Rein Tollevik Basefarm AS
Rein Tollevik writes:
The "sufficient" control should act like "stop" (i.e grant access) if the effective <access> is sufficient for the requested access level, "continue" otherwise.
It's <access> which grants access, "stop" just says "don't look for more access rules to apply". So this in particular makes me nervous:
The "requested" control should act like "continue" if the effective <access> matches what is requested, "break" otherwise.
because this:
access to <what> by * =w requested by <who> =w
actually grants everyone else than <who> access too, but only when they don't need it. That matters if something (now or in the future) combines and caches access levels for the duration of an operation, or checks the access level somehow and applies it "by hand".
An alternative would be to make it part of <what> and/or <who>: access to requested="=w" <rest of <what>> by <who> =w by * break That might still get problems with caching, but less severly so.
I suppose it could be defined as an optimization hint which slapd at least in theory may ignore, so it's a user error if the access rules are written so it makes a difference whether or not slapd applies it. But that wouldn't make it easier to understand the access rules:-(
Other notes:
It might be useful to allow stop/continue/break after requested/sufficient.
Is there a reason why you have different access tests? Effective access "is sufficient for" vs. "matches" requested access.
Hallvard B Furuseth wrote:
Rein Tollevik writes:
The "sufficient" control should act like "stop" (i.e grant access) if the effective <access> is sufficient for the requested access level, "continue" otherwise.
It's <access> which grants access, "stop" just says "don't look for more access rules to apply". So this in particular makes me nervous:
Yes, this was not the best wording.. It is not the "stop" by itself that grants access, but since "stop" would only be done after access had been tested to be granted the overall effect when the stop was taken would be to grant access.
The "requested" control should act like "continue" if the effective <access> matches what is requested, "break" otherwise.
because this:
access to <what> by * =w requested by <who> =w
actually grants everyone else than <who> access too, but only when they don't need it. That matters if something (now or in the future) combines and caches access levels for the duration of an operation, or checks the access level somehow and applies it "by hand".
The <access> in the "requested" control would have to be tested without being assigned to the effective access. Which is not how the other <access> assignments are evaluated :-(
Caching would have to include the requested access level. Given the dynamic nature of some ACL conditions (dynacl, sets), it is already questionably how much can be cached.. The current access_allowed() API returns a boolean grant/deny status for a requested access, so external "by hand" access level checks would, apart from being bad coding, not make any sense.
An alternative would be to make it part of <what> and/or <who>: access to requested="=w" <rest of <what>> by <who> =w by * break That might still get problems with caching, but less severly so.
Yes, this looks as a better approach than the "requested" control. But doing it belongs in another proposal.
I first thought of the "requested" control as "required", and it was a direct opposite to "sufficient". But I didn't find it very useful (at least for me), and it evolved into "requested". Which probably was an unfortunate diversion, since it differ from the current <access> concept.
I now think it is best to go back to "sufficient" and "required" (or some better names?). "sufficient" would "stop" if the effective <access> grants access, "continue" otherwise, while "required" would "stop" if the <access> denies access, "continue" otherwise.
The usage rules would be that "sufficient" can be used when all succeeding rules grants privileges above the <access> level, while "required" can be used when the succeeding rules all grants fewer privileges.
The current effective access level can be tested without altering it with an access of "+0" (or doing the equivalent of leaving it out).
And, provided the "continue" control would be taken in the no-stop case, the following would be equivalent (although the first variants should definitely not be the preferred):
access to * by * <access> sufficient access to * by * <access>
as would these:
access to * by * <access> required access to * by * none
These follows from the implicit "by * none" at the end of all ACLs.
I suppose it could be defined as an optimization hint which slapd at least in theory may ignore, so it's a user error if the access rules are written so it makes a difference whether or not slapd applies it. But that wouldn't make it easier to understand the access rules:-(
Other notes:
It might be useful to allow stop/continue/break after requested/sufficient.
Yes, I was thinking along those lines too, although I put them in the opposite order. I ditched it since it would introduce a new concept into the ACLs, which I didn't want to do. It would eliminate the problem of whether "continue" or "break" should be the actions in the no-stop case though..
Is there a reason why you have different access tests? Effective access "is sufficient for" vs. "matches" requested access.
Yes, the unfortunate diversion mentioned above...
Rein
Rein Tollevik wrote:
The current access_allowed() API returns a boolean grant/deny status for a requested access, so external "by hand" access level checks would, apart from being bad coding, not make any sense.
Forget this! I overlooked the maskp argument to access_allowed(), as well as the access_allowed_mask() function :-(
Rein
Rein Tollevik wrote:
I have a fairly complicated ACL set which I need to optimize the evaluation of. To do this I need to make decisions based on the requested access level, which currently isn't possible (as far as I know that is). E.g, most of my ACLs are concerned with whether the entries and attributes should be read or writable or not, and I would like to quickly grant search access when that is all that is requested.
One possibility I have considered is to add a new optional<requested access> field between the existing<who> and the<access> clauses, but I'm not very happy with that solution as it could easily be mixed with the existing<access>.
For what it's worth, HP had a similar requirement. We showed them how to write a dynacl module to intercept regular ACL processing and do what they needed. It seems to me that you should be able to at least prototype using dynacl first, to gain some experience with the real effects of these controls, before progressing further in the core code.
So far my preferred solution is to add two new ACL controls, which I currently think of as "sufficient" and "requested".