I need to retrieve the list of groups a user is in, using an LDAP query in Django. The use case is: a user fills in his LDAP login credentials, and Django will authenticate him and will also assign his LDAP groups .
The user login works flawlessly, but I cannot filter groups using memberUid=%(user)s
. I'm looking for the right method to pass the username as a filter argument to "groupfilter" property . I tested the query with an LDAP application browser and seems to work properly.
I'm using RatticWeb django application to manage users' passwords with the following local configuration (see also Rattic repository wiki ):
conf/local.cfg
[ldap]
requirecert = True
# LDAP server details
uri = ldap://localhost:port
# Bind DN
binddn = cn=admin,dc=mydomain
bindpw = mypassword
# User parameters
userbase = ou=Users,dc=mydomain
userfilter = (uid=%(user)s)
#userfilter = (objectClass=person)
userfirstname = givenName
userlastname = sn
useldapgroups = True
# Set up the basic group parameters.
groupbase = ou=Groups,dc=mydomain
groupfilter = (&(objectClass=posixGroup)(memberUid=%(user)s))
grouptype = PosixGroupType
# How do I find staff
#staff = cn=staff,ou=groups,dc=example,dc=com
loglevel = DEBUG
This configuration file is read by settings.py ( source code ):
ratticweb/settings.py
# Defaults to a bogus filter so that searching yields no errors in the log
AUTH_LDAP_GROUP_FILTER = confget('ldap', 'groupfilter', '(objectClass=_fake)')
AUTH_LDAP_USER_SEARCH = LDAPSearch(AUTH_LDAP_USER_BASE, ldap.SCOPE_SUBTREE, AUTH_LDAP_USER_FILTER)
AUTH_LDAP_GROUP_SEARCH = LDAPSearch(AUTH_LDAP_GROUP_BASE, ldap.SCOPE_SUBTREE, AUTH_LDAP_GROUP_FILTER)
Now, I need to filter LDAP group passing the username parameter coming from user login form, and I tried using the same format of userfilter but the server give me back the following error:
[Wed Jan 13 16:51:24.257325 2016] [:error] [pid 11280] 2016-01-13 16:51:24,256 [ERROR] Caught Exception while authenticating myusername
[Wed Jan 13 16:51:24.257438 2016] [:error] [pid 11280] Traceback (most recent call last):
[Wed Jan 13 16:51:24.257478 2016] [:error] [pid 11280] File "/usr/local/lib/python2.7/dist-packages/django_auth_ldap/backend.py", line 323, in authenticate
[Wed Jan 13 16:51:24.257515 2016] [:error] [pid 11280] self._get_or_create_user()
[Wed Jan 13 16:51:24.257550 2016] [:error] [pid 11280] File "/usr/local/lib/python2.7/dist-packages/django_auth_ldap/backend.py", line 539, in _get_or_create_user
[Wed Jan 13 16:51:24.257586 2016] [:error] [pid 11280] self._mirror_groups()
[Wed Jan 13 16:51:24.257620 2016] [:error] [pid 11280] File "/usr/local/lib/python2.7/dist-packages/django_auth_ldap/backend.py", line 638, in _mirror_groups
[Wed Jan 13 16:51:24.257697 2016] [:error] [pid 11280] group_names = self._get_groups().get_group_names()
[Wed Jan 13 16:51:24.257734 2016] [:error] [pid 11280] File "/usr/local/lib/python2.7/dist-packages/django_auth_ldap/backend.py", line 755, in get_group_names
[Wed Jan 13 16:51:24.257770 2016] [:error] [pid 11280] group_infos = self._get_group_infos()
[Wed Jan 13 16:51:24.257804 2016] [:error] [pid 11280] File "/usr/local/lib/python2.7/dist-packages/django_auth_ldap/backend.py", line 803, in _get_group_infos
[Wed Jan 13 16:51:24.257835 2016] [:error] [pid 11280] self._group_search)
[Wed Jan 13 16:51:24.257864 2016] [:error] [pid 11280] File "/usr/local/lib/python2.7/dist-packages/django_auth_ldap/config.py", line 374, in user_groups
[Wed Jan 13 16:51:24.257893 2016] [:error] [pid 11280] groups = search.execute(ldap_user.connection)
[Wed Jan 13 16:51:24.257928 2016] [:error] [pid 11280] File "/usr/local/lib/python2.7/dist-packages/django_auth_ldap/config.py", line 150, in execute
[Wed Jan 13 16:51:24.257957 2016] [:error] [pid 11280] filterstr = self.filterstr % filterargs
[Wed Jan 13 16:51:24.257990 2016] [:error] [pid 11280] TypeError: format requires a mapping
The constructor of LDAPSearch
populates its attributes as follows:
self.base_dn = 'groupbase = ou=Groups,dc=mydomain'
self.scope = ldap.SCOPE_SUBTREE
self.filterstr = '(&(objectClass=posixGroup)(memberUid=%(user)s))'
/usr/local/lib/python2.7/dist-packages/django_auth_ldap/config.py #150
def execute(self, connection, filterargs=()):
"""
Executes the search on the given connection (an LDAPObject). filterargs
is an object that will be used for expansion of the filter string.
The python-ldap library returns utf8-encoded strings. For the sake of
sanity, this method will decode all result strings and return them as
Unicode.
"""
try:
filterstr = self.filterstr % filterargs
results = connection.search_s(self.base_dn.encode('utf-8'),
self.scope,
filterstr.encode('utf-8'))
except ldap.LDAPError, e:
results = []
logger.error(u"search_s('%s', %d, '%s') raised %s" %
(self.base_dn, self.scope, filterstr, pprint.pformat(e)))
return self._process_results(results)
At last, I've found the solution:
conf/local.cfg
[ldap]
....
# Set up the basic group parameters.
groupbase = ou=Groups,dc=mydomain
groupfilter = (objectClass=posixGroup)
grouptype = PosixGroupType
...
The key factor is the use of the groupType PosixGroupType
, because the query on Groups would be filtered on the memberUid parameter by Django Auth LDAP (observe the else part of the user_groups
function:
class PosixGroupType(LDAPGroupType):
"""
An LDAPGroupType subclass that handles groups of class posixGroup.
"""
def user_groups(self, ldap_user, group_search):
"""
Searches for any group that is either the user's primary or contains the
user as a member.
"""
groups = []
try:
user_uid = ldap_user.attrs['uid'][0]
if 'gidNumber' in ldap_user.attrs:
user_gid = ldap_user.attrs['gidNumber'][0]
filterstr = u'(|(gidNumber=%s)(memberUid=%s))' % (
self.ldap.filter.escape_filter_chars(user_gid),
self.ldap.filter.escape_filter_chars(user_uid)
)
else:
filterstr = u'(memberUid=%s)' % (
self.ldap.filter.escape_filter_chars(user_uid),
)
search = group_search.search_with_additional_term_string(filterstr)
groups = search.execute(ldap_user.connection)
except (KeyError, IndexError):
pass
return groups
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.