Nested groups with mirroring using a single group DN as the base

506 views
Skip to first unread message

Aaron Morris

unread,
Feb 25, 2015, 4:30:13 PM2/25/15
to django-a...@googlegroups.com
Hello all,

Django 1.7.4
django_auth_ldap 1.2.5

My company runs a large LDAP directory using IBM Tivoli Directory Server.  The database is so large, it is not feasible to query all of the groups a user might be a member.  I have a single group that contains all of the other groups nested which I care about for this particular Django application.  The problem is the LDAP query is not finding groups of which my test IDs is a member.

LDAP authentication is indeed functioning when I just use basic LDAP authentication.



(The settings have been sanitized of identifying information as best as possible)

Settings:

AUTHENTICATION_BACKENDS = (
    'django_auth_ldap.backend.LDAPBackend',
    'django.contrib.auth.backends.ModelBackend',
)

AUTH_LDAP_SERVER_URI    = 'ldaps://ldapserver.foo.com/'
AUTH_LDAP_USER_SEARCH   = LDAPSearch('ou=users,o=foo.com', ldap.SCOPE_SUBTREE, '(mail=%(user)s)')
AUTH_LDAP_USER_ATTR_MAP = {
    'first_name' : 'givenName',
    'last_name'  : 'sn',
    'email'      : 'mail',
}

AUTH_LDAP_GROUP_SEARCH  = LDAPSearch('cn=Master Group,ou=groups,o=foo.com', ldap.SCOPE_SUBTREE, '(objectClass=groupOfUniqueNames)')
AUTH_LDAP_GROUP_TYPE    = NestedGroupOfUniqueNamesType(name_attr='cn')

# Disabled for testing
#AUTH_LDAP_REQUIRE_GROUP = 'cn=Master Group,ou=groups,o=foo.com'

AUTH_LDAP_ALWAYS_UPDATE_USER  = True
AUTH_LDAP_FIND_GROUP_PERMS    = True
AUTH_LDAP_MIRROR_GROUPS       = True
AUTH_LDAP_CACHE_GROUPS        = True
AUTH_LDAP_GROUP_CACHE_TIMEOUT = 3600

AUTH_LDAP_GLOBAL_OPTIONS = {
    ldap.OPT_X_TLS_REQUIRE_CERT : 0,
    ldap.OPT_TIMELIMIT          : 5,
}




Example ldapsearch:
$ ldapsearch -H ldaps://ldapserver.foo.com -b o=foo.com -x "cn=Master Group"

# Master Group, groups, foo.com
dn: cn=Master Group,ou=groups,o=foo.com
objectClass: ibm-nestedGroup
objectClass: groupOfUniqueNames
objectClass: top
ou: memberlist
o: foo.com
uniquegroup: cn=group1,ou=groups,o=foo.com
uniquegroup: cn=group2,ou=groups,o=foo.com
uniquegroup: cn=group3,ou=groups,o=foo.com
uniquegroup: cn=group4,ou=groups,o=foo.com
uniquegroup: cn=group5,ou=groups,o=foo.com

...etc...



Logs:

[Wed Feb 25 02:41:50 2015] [error] search_s('ou=users,o=foo.com', 2, '(mail=%(user)s)') returned 1 objects: uid=username,ou=users,o=foo.com
[Wed Feb 25 02:41:50 2015] [error] Populating Django user user...@foo.com
[Wed Feb 25 02:41:50 2015] [error] search_s('cn=Master Group,groups,o=foo.com', 2, '(&(objectClass=groupOfUniqueNames)(|(uniqueMember=uid=username,ou=users,o=foo.com)))') returned 0 objects:


Peter Sagerson

unread,
Feb 25, 2015, 4:40:03 PM2/25/15
to django-a...@googlegroups.com
Hi Aaron,

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.

Thanks,
Peter
> --
> You received this message because you are subscribed to the Google Groups "django-auth-ldap" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to django-auth-ld...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Aaron Morris

unread,
Feb 25, 2015, 4:49:01 PM2/25/15
to django-a...@googlegroups.com

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.

Now that I think about it, the other groups fall outside of my base DN, so that is probably why the search never returns anything.  Duh.



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.

Makes sense to me.  I will take a look.

Aaron Morris

unread,
Feb 26, 2015, 11:40:09 AM2/26/15
to django-a...@googlegroups.com
Here is my solution thus far.  This will find all of the nested groups within a single group and look for membership in said groups.  It only searches the first level of nested groups, I may extend this later to recursively search further levels.


This performs very well, returning dozens of groups among 100+ nested groups defined.  I realize that the resulting query may grow too large at some point, I may have to limit the query to something like 50-100 groups at a time.




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)




Aaron Morris

unread,
Feb 26, 2015, 12:13:05 PM2/26/15
to django-a...@googlegroups.com
I forgot to include usage:

AUTH_LDAP_GROUP_TYPE = NestedGroupOfSingleGroupType('cn=Master Group')

Benjamin SOULAS

unread,
Sep 5, 2018, 8:34:35 AM9/5/18
to django-auth-ldap
Hi Aaron, did you succeed in doing what you had to do?

Maybe It is too long, but I have a question because I have a similar project to develop. We will potentially have LDAP servers in which groups and subgroups exists, so with the code you implemented, it is possible to retrieve them. But how does the groups creation in Django ORM work? To be more precise, do it create each group and subgroup and subsubgroup (and so on) as a Django Group? If yes, how do you link the subgroups to their parents groups? Because natively, I did not find anything on that subject ...

Maybe the solution is to override Django native groups? I ask you this because I am mistaken because I understood (but apparently not) that django-auth-LDAP handle the subgroups case and make the right modifications in Django ORM

If you got an answer, even negative, thanks so much in advance.

Kind regards,

Benjamin

Di majo

unread,
May 12, 2024, 4:35:40 AM5/12/24
to django-auth-ldap
MT103/202 DIRECT WIRE TRANSFER
PAYPAL TRANSFER
CASHAPP TRANSFER
ZELLE TRANSFER
LOAN DEAL
TRANSFER WISE
WESTERN UNION TRANSFER
BITCOIN FLASHING
BANK ACCOUNT LOADING/FLASHING
IBAN TO IBAN TRANSFER
MONEYGRAM TRANSFER
IPIP/DTC
SLBC PROVIDER
CREDIT CARD TOP UP
DUMPS/ PINS
SEPA TRANSFER
WIRE TRANSFER
BITCOIN TOP UP
GLOBALPAY INC US
SKRILL USA
UNIONPAY RECEIVER

Thanks.


NOTE; ONLY SERIOUS / RELIABLE RECEIVERS CAN CONTACT.

DM ME ON WHATSAPP
+44 7529 555638
Reply all
Reply to author
Forward
0 new messages