https://bugs.openldap.org/show_bug.cgi?id=9256
--- Comment #16 from Karl O. Pinc kop@karlpinc.com --- Hi Ondřej,
On Wed, 28 Apr 2021 10:16:08 +0000 openldap-its@openldap.org wrote:
https://bugs.openldap.org/show_bug.cgi?id=9256
--- Comment #15 from Ondřej Kuzník ondra@mistotebe.net --- On Thu, Apr 08, 2021 at 08:12:18PM +0000, openldap-its@openldap.org wrote:
Thanks for the reply.
The attached patch contains a test script which, I believe, validates the (newly but not yet fully documented in the patch) access rules which are required to bind.
thanks for the patch. I don't understand many of the assertions below and don't understand what the test script is supposed to test, if you're saying it uncovers bugs, does it mean if fails for you? I doesn't fail for me even if I uncomment/enable parts that look like they're (temporarily) disabled.
The script succeeds, as written.
I believe it does uncover a bug. Or at least can be made to do so.
What it tests is for the exact access requirements needed to perform each "kind" of bind. It does this by proving that a particular set of access rights is both minimal and necessary.
It does this by using only access rules the are maximally specific. Each access rule grants only one permission to one authenticating DN on one attribute attribute of one entry. When access rules are written this way, removing a single rule will prevent the authenticating DN from binding.
Each bind test has a set of these access rules. The script checks that the bind succeeds with the rules, proving that the access rules permit binding. Then it checks that the bind fails when any one of the access rules is removed, proving that each permission is required.
This method is the only way I can see to demonstrate what ACLs are required to bind, and so prove that the documentation is correct and that the requirements do not change from release to release.
As an FYI unrelated to the topic at hand, the script loops through the "set of binds" twice. First with an olcAuthzRegexp that does ldap searching, with a replace name beginning with "ldap:", and again using direct dn mapping, with a replace name beginning with "dn:". The access rules vary between these two cases so there are functions called to create the rules. The idea was to show what's common. The functions do obscure what's different, so I would up printing the set of access rules in order to have something to look at.
However, I believe I have uncovered another bug. It appears that, even when every access rule applies _only_ to a single DIT entry, one attribute of that entry, and grants access to _only_ a single DN, the access rules are sensitive to ordering. Some access rules are required, given a particular ordering of the access rules, that are not required when the rules are re-ordered.
ACLs are order-sensitive, could you give an example?
The below two ALCs should not be order sensitive, because they are "maximally specific" as defined above. (Unless, of course, there are other interspersed ACLS that are not maximally specific, do not end with "by * break", etc.)
olcAccess: to dn.exact="cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=exam ple,dc=com" attrs=userpassword by anonymous =x by * break
olcAccess: to dn.exact="cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=exam ple,dc=com" attrs=entry by anonymous =x by * break
Search for "ORDERING BUG" in the test script for an example. (The code there is run twice, once with an authz-regexp with a URI and again with an authz-regexp that does direct DN mapping with a regexp.)
Again, this doesn't fail for me and nothing there suggests what the alternative set up should be to make it expose a bug.
But this series of tests is not written to expose that bug, it's written to affirm that the documented minimal ACLs necessary to bind are correct. (See below for more.)
The supplied test case does not test every permutation of the given access rules, which leaves open the possibility that it is not discovering all the access rules that are required; and the supplied documentation patch does not mention any ordering requirements for access rules and so is likely incomplete.
I don't believe that access rules should be order dependent unless, obviously, there exist some rules that apply to the same portion of the DIT and also grant access to more than one authenticating entity.
Could you give an explicit example?
This is what "ORDERING BUG" uncovers, if you do as the comment says. The command is:
../clients/tools/ldapwhoami -Q -H ldap://localhost:9011/ -Y DIGEST-MD5 -U "Barbara Jensen:Information Technology Division" -w bjensen
The mapping is:
olcAuthzRegexp: "^uid=([^:]+):([^,]+),.*" "dn:cn=$1,ou=$2,ou=people,dc=example,dc=com"
The following access rules are proved, as the script is written which delivers the rules in the order given below, to be the minimal needed to bind:
olcAccess: to dn.exact="cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com" attrs=userpassword by anonymous =x by * break
olcAccess: to dn.exact="cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com" attrs=entry by anonymous =x by * break
olcAccess: to dn.exact="cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com" attrs=objectClass by anonymous =x by * break
olcAccess: to dn.exact="dc=example,dc=com" attrs=entry by anonymous =x by * break
olcAccess: to * by * none stop
However, if you follow the instructions in the "ORDERING BUG" section and re-order the access rules to the following:
olcAccess: to dn.exact="cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com" attrs=userpassword by anonymous =x by * break
olcAccess: to dn.exact="cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com" attrs=entry by anonymous =x by * break
olcAccess: to dn.exact="dc=example,dc=com" attrs=entry by anonymous =x by * break
olcAccess: to dn.exact="cn=Barbara Jensen,ou=Information Technology Division,ou=People,dc=example,dc=com" attrs=objectClass by anonymous =x by * break
olcAccess: to * by * none stop
Then what you find is that the rule:
olcAccess: to dn.exact="dc=example,dc=com" attrs=entry by anonymous =x by * break
is unnecessary. The bind can be performed without it and so the script fails.
At this point I gave up. Anything, especially previous binds if there's some sort of caching involved, could be causing this and I didn't try to come up with a minimal example. I can tell you that you can comment out line #2467, which removes all the mappings to "ldap:" urls and leaves only the olcAuthzRegexp with the "dn:" mappings, and the problem still exhibits.
My problem is that if you can't test for minimal access rights required to bind by removing ACLs until you get a minimal set, then there's no way to know or document what the minimal access rights are.
In theory, the test script could do more than remove access rights to come up with a minimal set. It could also re-order all the access rights and test all permutations to prove that when all access rights are "maximally specific", ACLs are not sensitive to order. (As I believe should be the case.) This is probably prudent, to prove that the bug I believe I've discovered is fixed. At least with respect to binding. But all of this is out-of-scope with respect to documenting access rights, which is what I want to do.
P.S. Work on the test case is what uncovered bug# 9495. I wound up using a ":" character in the authzid to work-around the problem, and made corresponding adjustments to the authz-regexp(s). When 9495 is fixed you may want to fiddle with the test script and do "something different"; or not.
If you consider the authzid provided by the client has to go through normalisation as per RFC4513 Section 5.2.1.8, would you comment on ITS#9495 whether/or to what extent it might explain your findings?
I mention ITS#9495 here because this script discovered the problem. I don't believe that it really has to do with this script, other than when ITS#9495 is fixed this script might be changed so that the mappings happen in a more natural way. ITS#9495 explains why this script's mappings are "different".
Regards,
Karl kop@karlpinc.com Free Software: "You don't pay back, you pay forward." -- Robert A. Heinlein