Getting groups from LDAP to django

Marius picture Marius · Nov 27, 2013 · Viewed 8.5k times · Source

I am using django-ldap-auth to authenticate users against an LDAP-Server (ActiveDirectory). The users are able to login and the flags per user (e.g. is_staff) are set correctly.

I also want to add django-groups to my django-users depending on the ldap-users group. Here're my settings:

import ldap
from django_auth_ldap.config import LDAPSearch, GroupOfNamesType, ActiveDirectoryGroupType

AUTH_LDAP_SERVER_URI = "ldap://XXX"

AUTH_LDAP_BIND_AS_AUTHENTICATING_USER = True
AUTH_LDAP_BIND_DN = ""
AUTH_LDAP_BIND_PASSWORD = ""

# I somewhere read that this should help, but it didn't:
#AUTH_LDAP_GLOBAL_OPTIONS = {
#    ldap.OPT_REFERRALS: 0
#}

AUTH_LDAP_USER_SEARCH = LDAPSearch("ou=Benutzer,ou=Konten,ou=XXX,ou=XXX,dc=XXX,dc=XXX,dc=XXX",
ldap.SCOPE_SUBTREE, "(cn=%(user)s)")
AUTH_LDAP_USER_DN_TEMPLATE = "CN=%(user)s,OU=Benutzer,OU=Konten,OU=XXX,OU=XXX,DC=XXX,DC=XXX,DC=XXX"

# Set up the basic group parameters.
AUTH_LDAP_GROUP_SEARCH = LDAPSearch("OU=AnwenderRollen,OU=Gruppen,OU=XXX,OU=XXX,DC=XXX,DC=XXX,DC=XXX",
    ldap.SCOPE_SUBTREE, "(objectClass=groupOfNames)"
)
AUTH_LDAP_GROUP_TYPE = GroupOfNamesType(name_attr="CN")
# also tried various possibilities for objectClass and AUTH_LDAP_GROUP_TYPE
#AUTH_LDAP_GROUP_TYPE = GroupOfNamesType(name_attr="cn")
#AUTH_LDAP_GROUP_TYPE = ActiveDirectoryGroupType(name_attr="cn")


# Populate the Django user from the LDAP directory.
AUTH_LDAP_USER_ATTR_MAP = {
    "first_name": "givenname",
    "last_name": "sn",
    "email": "mail"
}

AUTH_LDAP_PROFILE_ATTR_MAP = {
    #"employee_number": "employeeNumber"
}

AUTH_LDAP_USER_FLAGS_BY_GROUP = {
    #"is_active": "cn=active,ou=django,ou=groups,dc=example,dc=com",
    "is_staff": "CN=GROUPNAME,OU=AnwenderRollen,OU=Gruppen,ou=XXX,ou=XXX,dc=XXX,dc=XXX,dc=XXX",
    "is_superuser": "CN=GROUPNAME,OU=AnwenderRollen,OU=Gruppen,ou=XXX,ou=XXX,dc=XXX,dc=XXX,dc=XXX"
}

AUTH_LDAP_PROFILE_FLAGS_BY_GROUP = {
    #"is_awesome": "cn=awesome,ou=django,ou=groups,dc=example,dc=com",
}

# This is the default, but I like to be explicit.
AUTH_LDAP_ALWAYS_UPDATE_USER = True

# Use LDAP group membership to calculate group permissions.
AUTH_LDAP_FIND_GROUP_PERMS = True

# Cache group memberships for an hour to minimize LDAP traffic
AUTH_LDAP_CACHE_GROUPS = True
AUTH_LDAP_GROUP_CACHE_TIMEOUT = 1 #3600

# Keep ModelBackend around for per-user permissions and maybe a local
# superuser.
AUTHENTICATION_BACKENDS = (
    'django_auth_ldap.backend.LDAPBackend',
    'django.contrib.auth.backends.ModelBackend',
)

Only parts of this settings work: Login works, a django-user is created, the attributes are taken from LDAP (AUTH_LDAP_USER_ATTR_MAP) and the flags are set (AUTH_LDAP_USER_FLAGS_BY_GROUP) with the same group-path as in AUTH_LDAP_GROUP_SEARCH. But this group search does not work because of this error:

DEBUG Populating Django user USERNAME
DEBUG search_s('CN=USERNAME,OU=Benutzer,OU=Konten,ou=XXX,ou=XXX,dc=XXX,dc=XXX,dc=XXX', 0, '(objectClass=*)') returned 1 objects: cn=USERNAME,ou=benutzer,ou=konten,ou=XXX,ou=XXX,dc=XXX,dc=XXX,dc=XXX
DEBUG CN=USERNAME,OU=Benutzer,OU=Konten,ou=XXX,ou=XXX,dc=XXX,dc=XXX,dc=XXX is a member of cn=GROUPNAME,ou=anwenderrollen,ou=gruppen,ou=XXX,ou=XXX,dc=XXX,dc=XXX,dc=XXX
DEBUG CN=USERNAME,OU=Benutzer,OU=Konten,ou=XXX,ou=XXX,dc=XXX,dc=XXX,dc=XXX is a member of cn=GROUPNAME,ou=anwenderrollen,ou=gruppen,ou=XXX,ou=XXX,dc=XXX,dc=XXX,dc=XXX
DEBUG Django user USERNAMEdoes not have a profile to populate
ERROR search_s('OU=AnwenderRollen,OU=Gruppen,ou=XXX,ou=XXX,dc=XXX,dc=XXX,dc=XXX', 2, '(&(objectClass=groupOfNames)(member=CN=USERNAME,OU=Benutzer,OU=Konten,ou=XXX,ou=XXX,dc=XXX,dc=XXX,dc=XXX))') raised OPERATIONS_ERROR({'info': '00000000: LdapErr: DSID-0C090627, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, vece', 'desc': 'Operations error'},)
DEBUG search_s('OU=AnwenderRollen,OU=Gruppen,ou=XXX,ou=XXX,dc=XXX,dc=XXX,dc=XXX', 2, '(&(objectClass=groupOfNames)(member=CN=USERNAME,OU=Benutzer,ou=XXX,ou=XXX,dc=XXX,dc=XXX,dc=XXX))') returned 0 objects: 

Since the group-paths are the same for the flags and for the group search I was assuming that it should work. Is it a problem to search for groups when binding as authenticating user?

What am I missing?

Answer

Marius picture Marius · Dec 5, 2013

Here's what I did to make it work:

AUTH_LDAP_BIND_AS_AUTHENTICATING_USER = True
AUTH_LDAP_BIND_DN = "existing_user"
AUTH_LDAP_BIND_PASSWORD = "existing_password"

and I changed (objectClass=groupOfNames) to (objectClass=top)

It seems that django_auth_ldap uses the bound user to check for the flags (is_staff, ...) but not to check the groups. So I added credentials to these variables which are now used to search for groups.

However, it works!