spring-ldap icon indicating copy to clipboard operation
spring-ldap copied to clipboard

ODM for a group with lot of members are not fetched correctly

Open susil opened this issue 5 years ago • 9 comments
trafficstars

Hi I have Group ODM class as below:

` @Entry(objectClasses = { "group", "top" }, base = "OU=group")

public final class ADGroup implements Serializable {

 private static final long serialVersionUID = 915331212576640803L;
 
@Id
private Name dn;

@Attribute(name = "cn")
@DnAttribute(value="cn", index=1)
private String name;

@Attribute(name = "member")
private Set<Name> members;

public Name getDn() {
    return dn;
}

public void setDn(Name dn) {
    this.dn = dn;
}

public Set<Name> getMembers() {
    return members;
}

public void setMembers(Set<Name> members) {
    this.members = members;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public void addMember(Name member) {
    members.add(member);
}

public void removeMember(Name member) {
    members.remove(member);
}

}`

When I get this ODM class using the ldapTempalte as below

` ADGroup adGuest = aDldapTemplate.findOne(query().where("cn").is("MyGroup"), ADGroup.class); Set<Name> members = adGuest.getMembers(); log.info("members.size()="+members.size());

` I see the ODM class mapped to AD group correctly and when I turn on log to trace level I do see member accounts which comes in as

{member;range=0-1499[0]=CN=abc1....,member;range=0-1499[1]=CN=abc2 ....until, member;range=0-1499[1499]=CN=abc1499

I understand this due to set count limit set on Active Directory that only allows certain count of members. And when this happens, "member" attribute is not correctly mapped and "adGuest.getMembers();" does not show the correct count of (1500 ) but just shows 0.

I do not want to change AD bind setting to get all the data at once because it could be huge, but I do want to be able to run pageable like option to get all the records. When I tested this with group with smaller number of members (,1500), it worked just fine, giving the right count and member info as well.

So question is; Is there a way make this pageable like query and fetch all the records ? If so how to do this. Is there some annotation that I need to provide in ODM class itself or is that done in aDldapTemplate.findOne like call. It will be great to get some insight on this with code snippet to do this.

Thank you in advance Su

susil avatar Jun 25 '20 23:06 susil

Hi All, Any help/idea on this will be highly appreciated.

Thanks Su

susil avatar Jul 23 '20 22:07 susil

I have the same problem. @susil, Did you fix it?

jbazp avatar Jun 14 '21 09:06 jbazp

same problem!!!!!! any ideas?

enzolcastro avatar Feb 17 '22 20:02 enzolcastro

member;range=0-1499[1499]

enzolcastro avatar Feb 17 '22 20:02 enzolcastro

i have 25000 records....

enzolcastro avatar Feb 17 '22 20:02 enzolcastro

In the spring-data project there is a test that gets more than 1500 values ​​of an attribute. I used that test as a reference and it worked for me: https://github.com/spring-projects/spring-ldap/blob/main/test/integration-tests-ad/src/test/java/org/springframework/ldap/itest/ad/IncrementalAttributeMapperITest.java#L153


 protected IncrementalAttributesMapper<DefaultIncrementalAttributesMapper> getDefaultIncrementalAttributesMapper() {
        return new DefaultIncrementalAttributesMapper(new String[] { "member", "cn" });
 }

protected ArrayList<String> retrievalALotOfAttributeValues(Name dn) {
        var result = new ArrayList<String>();
        final var ctx = ldapTemplate.lookupContext(dn);
        if (ctx.getStringAttribute("member") == null) {
            var attributeMapper = getDefaultIncrementalAttributesMapper();

            while (attributeMapper.hasMore()) {
                attributeMapper = ldapTemplate.lookup(dn, attributeMapper.getAttributesForLookup(), attributeMapper);
            }

            final var memberValues = attributeMapper.getValues("member");
            if (memberValues != null) {
                result = (ArrayList<String>) memberValues.stream().map(object -> object.toString()).collect(Collectors.toList());
            }
        }
        return result;
    }

jbazp avatar Feb 17 '22 21:02 jbazp

I need remove an user (i have the DN) from a Group with 25790 members. So this work for that? obviusly i need to write the code for ldaptemplate.modify

enzolcastro avatar Feb 18 '22 12:02 enzolcastro

Could this be the reason why addIfDuplicateExists argument doesn't work correctly? Our code looks similar to this:

DirContextOperations dirContextOperations = ldapTemplate.lookupContext(groupDn);
boolean addIfDuplicateExists = false;
dirContextOperations.addAttributeValue("member", userDn, addIfDuplicateExists);
ldapTemplate.modifyAttributes(dirContextOperations);

It works for all groups except one group with more than 1500 members´, which causes following exception:

org.springframework.ldap.AttributeInUseException: (...) 0: 00002083: DSID-03151F38, problem 1006 (ATT_OR_VALUE_EXISTS), data 0, Att 1f (member):len 188 (...)

@jbazp If the test/mock LDAP server has no value count limit for multi value attributes the integration test will be successful even if the problem exists.

We can also see the limit in our LDAP tool. Where other groups' attribute is called "member", it's called "member;range=0-1499" for this one group with more than 1500 members.

fishbone1 avatar Jul 11 '23 10:07 fishbone1

@jbazp Ah I misunderstood your comment with the integration test. I thought you are saying that it should work as expected because the test would fail otherwise. But instead the test contains the solution. I wonder why this isn't the default behavior. I try to adapt this for my case with addIfDuplicateExists

fishbone1 avatar Jul 11 '23 11:07 fishbone1