Domanda

I am not having any luck finding answers on this, so here it goes.

When I attemtp to connect to an AD server using python-ldap, it appears to work successfully for some functions, and not for others. My connection:

>>>import sys
>>>import ldap

>>>l = ldap.initialize("ldap://company.com:389")
>>>l.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
>>>l.simple_bind_s("user@company.com","password")
(97, [], 1, [])

Some simple google searching indicated that the 97 meant success, although the level of success is a bit wonky. But, for some reason, I cant find anything on the status code 1. If I run some ldap functions on the connection, some of them work and some do not.

>>>l.whoami_s()
'u:COMPANY.COM\\user'

Seems to return fine, but

>>> base_dn = 'dc=company,dc=com'
>>> retrieveAttributes = ["uniquemember"]
>>> searchFilter = "cn=user"
>>> l.search_s(base_dn, ldap.SCOPE_SUBTREE,searchFilter,retrieveAttributes)
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/home/user/.envs/scoring/local/lib/python2.7/site-packages/ldap/ldapobject.py", line 552, in search_s
    return self.search_ext_s(base,scope,filterstr,attrlist,attrsonly,None,None,timeout=self.timeout)
  File "/home/user/.envs/scoring/local/lib/python2.7/site-packages/ldap/ldapobject.py", line 546, in search_ext_s
    return self.result(msgid,all=1,timeout=timeout)[1]
  File "/home/user/.envs/scoring/local/lib/python2.7/site-packages/ldap/ldapobject.py", line 458, in result
    resp_type, resp_data, resp_msgid = self.result2(msgid,all,timeout)
  File "/home/user/.envs/scoring/local/lib/python2.7/site-packages/ldap/ldapobject.py", line 462, in result2
    resp_type, resp_data, resp_msgid, resp_ctrls = self.result3(msgid,all,timeout)
  File "/home/user/.envs/scoring/local/lib/python2.7/site-packages/ldap/ldapobject.py", line 469, in result3
    resp_ctrl_classes=resp_ctrl_classes
  File "/home/user/.envs/scoring/local/lib/python2.7/site-packages/ldap/ldapobject.py", line 476, in result4
    ldap_result = self._ldap_call(self._l.result4,msgid,all,timeout,add_ctrls,add_intermediates,add_extop)
  File "/home/user/.envs/scoring/local/lib/python2.7/site-packages/ldap/ldapobject.py", line 99, in _ldap_call
    result = func(*args,**kwargs)
OPERATIONS_ERROR: {'info': '000004DC: LdapErr: DSID-0C0906E8, comment: In order to perform this operation a successful bind must be completed on the connection., data 0, v1db1', 'desc': 'Operations error'}

I am stumped to why the whoami would work but the search would not. I am using a domain admin for the user, so it shouldn't have anything to do with permissions to the directory. Can anyone shed some light?

È stato utile?

Soluzione

I was getting the exact same error as you, what I did was adding this line (as suggested by Christopher), l.set_option(ldap.OPT_REFERRALS, 0) before doing the binding, e.g.

conn.protocol_version = ldap.VERSION3
conn.set_option(ldap.OPT_REFERRALS, 0)
conn.simple_bind_s(user, pw)

And after that my connection to LDAP worked fine.

Altri suggerimenti

Based on what @Cas said above, I only had to add:

connection.set_option(ldap.OPT_REFERRALS,0)

It looks like this is such a common problem that it was added to the python-ldap FAQ:

Q: My script bound to MS Active Directory but a a search operation results in an exception ldap.OPERATIONS_ERROR with the diagnostic messages text "In order to perform this operation a successful bind must be completed on the connection.". What's happening here?

A: When searching from the domain level MS AD returns referrals (search continuations) for some objects to indicate to the client where to look for these objects. Client-chasing of referrals is a broken concept since LDAPv3 does not specify which credentials to use when chasing the referral. Windows clients are supposed to simply use their Windows credentials but this does not work in general when chasing referrals received from and pointing to arbitrary LDAP servers. Therefore per default libldap automatically chases the referrals internally with an anonymous access which fails with MS AD. So best thing is to switch this behaviour off:

l = ldap.initialize('ldap://foobar')

l.set_option(ldap.OPT_REFERRALS,0)

Try:

import ldap

connect = ldap.initialize("ldap://example.com")
connect.set_option(ldap.OPT_REFERRALS, 0)
try:
    connect.simple_bind_s(login, password)
    connect.search_s("dc=example,dc=com",
                     ldap.SCOPE_SUBTREE,
                     'userPrincipalName={}'.format(login),
                     ['cn'])
except (ldap.INVALID_CREDENTIALS, ldap.OPERATIONS_ERROR):
    return False
retrurn True

So here we binding LDAP with our credentials, and if no error was raised, we try to perform search for our user’s CN in LDAP. And if there was an empty password and this is not correct, here will be raised OPERATIONS_ERROR, because no actual bind with credentials was performed.

If you get this error when using flask-simpleldap, you can use this oneliner:

app.config['LDAP_CUSTOM_OPTIONS'] = {l.OPT_REFERRALS: 0}

See an example here.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top