I think the immediate answer is that AUTH_LDAP_GROUP_SEARCH needs to encompass all of the groups that you will want to know about. The search for nested groups is implemented by repeatedly querying for subsets of the group space.
Skipping ahead a bit, I suspect that the best solution here is to just write your own group implementation. The API is very simple, but you can do as much custom LDAP-fu as you need to to produce your list of groups. Take a look at the source code in django_auth_ldap.config for subclassing instructions and, obviously, examples.
from django_auth_ldap.config import LDAPGroupType
class NestedGroupOfSingleGroupType(LDAPGroupType):
def __init__(self, base_group_cn, name_attr='cn', member_attr='uniqueMember', groupmember_attr='uniqueGroup'):
self.base_group_cn = base_group_cn
self.name_attr = name_attr
self.member_attr = member_attr
self.groupmember_attr = groupmember_attr
super(NestedGroupOfSingleGroupType, self).__init__(name_attr)
def user_groups(self, ldap_user, group_search):
all_groups_cn_set = set()
base_group_search = group_search.search_with_additional_term_string(u'({0:s})'.format(self.base_group_cn))
base_group_r = base_group_search.execute(ldap_user.connection)
if(not base_group_r):
# Group not found
return tuple()
(base_group_dn, base_group_entry) = base_group_r[0]
for group_dn in base_group_entry[self.groupmember_attr]:
group_cn = (group_dn.split(u','))[0]
all_groups_cn_set.add(u'({0:s})'.format(group_cn))
all_groups_filter = u'(|{0:s})'.format(u''.join(all_groups_cn_set))
user_in_groups_filter = u'(&({0:s}={1:s}){2:s})'.format(self.member_attr, ldap_user.dn, all_groups_filter)
member_group_search = group_search.search_with_additional_term_string(user_in_groups_filter)
return member_group_search.execute(ldap_user.connection)