Sunday, March 3. 2019
Emulating the AD range attribute retrieval feature
Another quick entry today, I have been involved in a keycloak problem with windows AD. The issue can be summarized in the idea that the Active Directory, when an entry has a lot of values in one attribute (usually a group entry with a lot of users inside member), not all of them are returned by default. There is a MaxValRange limit that controls when the AD starts to omit values and return the values in ranges. Microsoft documents this feature in this note Searching Using Range Retrieval with some useful examples.
Configuring the limit to its lower value (30) in one of my demo envs the results in my tests were the following:
Retrieving the members from a group with 31 users activates the limit, and only 0-29 values are returned.
ldapsearch -LLL -h sampleserver.sample.com -D "cn=Admin,cn=Users,dc=sample,dc=com" -w XXXXX -b "CN=InnerGroup,ou=groups,dc=sample,dc=com" -s base objectclass=* member dn: CN=InnerGroup,ou=groups,dc=sample,dc=com member;range=0-29: CN=aduser5 aduser5,CN=Users,DC=SAMPLE,DC=COM member;range=0-29: CN=aduser4 aduser4,CN=Users,DC=SAMPLE,DC=COM ... member;range=0-29: CN=Administrator,CN=Users,DC=SAMPLE,DC=COM
The missing entry can be obtained requesting more data from 30 to the end (* means the the last attribute value):
ldapsearch -LLL -h sampleserver.sample.com -D "cn=Admin,cn=Users,dc=sample,dc=com" -w XXXXX -b "CN=InnerGroup,ou=groups,dc=sample,dc=com" -s base objectclass=* "member;range=30-*" dn: CN=InnerGroup,ou=groups,dc=sample,dc=com member;range=30-*: CN=aduser6 aduser6,CN=Users,DC=SAMPLE,DC=COM
You can also request just a specific range of the attribute (for example entries 28-29):
ldapsearch -LLL -h sampleserver.sample.com -D "cn=Admin,cn=Users,dc=sample,dc=com" -w XXXXX -b "CN=InnerGroup,ou=groups,dc=sample,dc=com" -s base objectclass=* "member;range=28-29" dn: CN=InnerGroup,ou=groups,dc=sample,dc=com member;range=28-29: CN=aduser5 aduser5,CN=Users,DC=SAMPLE,DC=COM member;range=28-29: CN=aduser4 aduser4,CN=Users,DC=SAMPLE,DC=COM
If the upper limit is greater than the current number of values in the attribute * is returned to mark that the last value was reached:
ldapsearch -LLL -h sampleserver.sample.com -D "cn=Admin,cn=Users,dc=sample,dc=com" -w XXXXX -b "CN=InnerGroup,ou=groups,dc=sample,dc=com" -s base objectclass=* "member;range=29-40" dn: CN=InnerGroup,ou=groups,dc=sample,dc=com member;range=29-*: CN=aduser6 aduser6,CN=Users,DC=SAMPLE,DC=COM member;range=29-*: CN=aduser5 aduser5,CN=Users,DC=SAMPLE,DC=COM
What happens if the upper range requested is wrong or less than the start range? Just one element is returned.
ldapsearch -LLL -h sampleserver.sample.com -D "cn=Admin,cn=Users,dc=sample,dc=com" -w XXXXX -b "CN=InnerGroup,ou=groups,dc=sample,dc=com" -s base objectclass=* "member;range=29-10" dn: CN=InnerGroup,ou=groups,dc=sample,dc=com member;range=29-29: CN=aduser5 aduser5,CN=Users,DC=SAMPLE,DC=COM
And if the start position is wrong? An error is returned.
ldapsearch -LLL -h sampleserver.sample.com -D "cn=Admin,cn=Users,dc=sample,dc=com" -w XXXXX -b "CN=InnerGroup,ou=groups,dc=sample,dc=com" -s base objectclass=* "member;range=50-*" Operations error (1) Additional information: 00002121: SvcErr: DSID-031206B8, problem 5012 (DIR_ERROR), data 8995
So the range retrieval is easy to use and understand but my main problem was that I needed to test this feature inside keycloak. The basic tests use the apache directory server embedded inside the same java code to test everything with maven. This range retrieval feature is very AD specific (I do not know any other LDAP directory that performs the same) so the Apache implementation does not do the same by default. But the project lets you implement your own interceptors. And, no sooner said than done, I implemented a ranged interceptor to emulate AD behavior. My implementation is very easy, it only applies to one attribute that should be specified, but range attribute value retrieval can be emulated in an embedded LDAP server for it, so I can write some tests to check if the implementation is working smoothly.
The entry's goal is just saving my interceptor here. It is just one class and some easy junit tests that check everything is working, but better if the class is saved here. The maven project can be downloaded from here.
Best regards!
Comments