ldap3操作:SEARCH似乎失败(search_filter语法与RFC4515)

时间:2015-09-21 12:50:12

标签: python-3.4 django-1.8 python-ldap

编辑:tl; dr - SEARCH中使用的search_filter参数可能不符合RFC4515。

我在Ubuntu 14.04上运行了一个运行1.8.4版本的Django服务器。我正在使用Python 3.4,为此我尝试使用ldap3配置LDAP身份验证。

这是分别从1.6.2,12.04和2.7.3升级到上述版本的一部分。一切都正常,所以我认为问题出在我的最后,而不是身份验证服务器。

这样做的方法是我有一个名为 authenticate_user.py 的文件,它接收通过HTML表单传递的用户名和密码,如下所示。

def authenticateStudent(request):
    username = request.POST.get('username','')
    logger.info("User " + username + " has logged in.")
    password = request.POST.get('password','')
    x = Auth(username, password)
    retVal = x.AuthenticatePy()
    logger.info('retVale is '+str(retVal)) #this returns False
    #more code and more logging

该方法从Auth类中实例化一个对象(如下所示),将用户名和密码存储在其中,然后调用该类中的AuthenticatePy()方法。

import logging
import sys
import os.path,subprocess
import ldap3 as ldap
from ldap3 import Connection, Server, SIMPLE, SYNC, SUBTREE, ALL


logger = logging.getLogger('Submission')

class Auth():

    studentName = ""
    studentEmail = ""
    studentMatrik = ""

    def __init__(self, username, password):
        self.username = username
        self.password = password

    def AuthenticatePy(self):
        user_dn = "cn="+self.username+",ou=users,ou=data,ou=prod,ou=authserver,dc=domain,dc=tld"
        base_dn = "dc=domain,dc=tld"
        server = Server("authserver.domain.tld", port=636, use_ssl=True)

        filter = "uid="+self.username #might be incorrect
        try:
            #if authentication successful, get the full user data
            connect = Connection(server, user=user_dn, password=self.password)
            connect.bind()
            logger.info('Connection Bind Complete!') #the last logged message from this method
            result = connect.search(search_base=base_dn, search_filter=filter, search_scope=SUBTREE)
            logger.info('SEARCHING COMPLETE') #does not appear in the log
            # return all user data results
            connect.unbind()
            uname = result[0][1]['cn'][0]
            studentName = result[0][1]['fullName'][0]
            studentEmail = result[0][1]['imHauptEMail'][0]
            studentMatrik = result[0][1]['imMatrikelNr'][0]
            logger.info('studentName is '+str(studentName))
            if uname == self.username :
                return studentName + '$' + studentEmail + '$' + studentMatrik
            else:
                return False
        except ldap.LDAPExceptionError:
            connect.unbind()
            return False

我看到的最后一条日志消息是“Connection Bind Complete!”而且我不确定是什么打破了。知道我做错了吗?

编辑:我已经对此进行了一段时间的故障排除,我开始认为问题可能出在我通过搜索功能的search_filter参数中。关于SEARCH操作的ldap3文档声明过滤器字符串应该符合RFC4515,我不确定我是否提供。

2 个答案:

答案 0 :(得分:7)

我是ldap3的作者。 ldap过滤器必须包含在括号中。请尝试将前导和尾随括号添加到过滤器:

filter =“(uid =”+ self.username +“)”

再见 乔瓦尼

答案 1 :(得分:0)

我设法解决了这个问题。我对search_filter参数的语法确实是错误的。

需要按照其他答案中的说明进行设置:
filter = "(uid="+self.username + ")"

但是,我还需要指出我想要返回哪些属性,因此connect.search()的参数需要更改:

connect.search(search_base=base_dn, search_filter=filter, search_scope=SUBTREE, attributes=['cn', 'fullName', 'imHauptEmail', 'imMatrikelNr'])

此外,访问返回的属性的方式与在Python 2.7的python-ldap库中的方式不同,可以通过connect.response访问,这是一个字典列表。在取消绑定连接之前,您必须访问这些属性,因此connect.unbind()被移动,直到存储了属性所需的值。

uname = str(connect.response[0]['attributes']['cn'][0])
studentName = str(connect.response[0]['attributes']['fullName'][0])
studentEmail = str(connect.response[0]['attributes']['imHauptEMail'][0])
studentMatrik = str(connect.response[0]['attributes']['imMatrikelNr'][0])
connect.unbind()

实际上所有这些都在documentation中解释(参见底部的示例部分)。我只需要阅读几次即可获得它。