Search code examples
pythonldappython-ldap

Python-ldap ldap.initialize rejects a URL that ldapurl considers valid


I want to open a connection to a ldap directory using ldap url that will be given at run time. For example :

ldap://192.168.2.151/dc=directory,dc=example,dc=com

It is valid as far as I can tell. Python-ldap url parser ldapurl.LDAPUrl accepts it.

url = 'ldap://192.168.2.151/dc=directory,dc=example,dc=com'
parsed_url = ldapurl.LDAPUrl(url)
parsed_url.dn
'dc=directory,dc=example,dc=com'

But if I use it to initialize a LDAPObject, I get a ldap.LDAPError exception

ldap.initialize(url)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/dist-packages/ldap/functions.py", line 91, in initialize
    return LDAPObject(uri,trace_level,trace_file,trace_stack_limit)
  File "/usr/lib/python2.7/dist-packages/ldap/ldapobject.py", line 70, in __init__
    self._l = ldap.functions._ldap_function_call(ldap._ldap_module_lock,_ldap.initialize,uri)
File "/usr/lib/python2.7/dist-packages/ldap/functions.py", line 63, in _ldap_function_call
  result = func(*args,**kwargs)
ldap.LDAPError: (0, 'Error')

I found that if I manually encode the dn part of the url, it works :

url = 'ldap://192.168.2.151/dc=directory%2cdc=example%2cdc=com'

#url still valid
parsed_url = ldapurl.LDAPUrl(url)
parsed_url.dn
'dc=directory,dc=example,dc=com'

#and will return a valid connection
ldap.initialize(url)
<ldap.ldapobject.SimpleLDAPObject instance at 0x1400098>

How can I ensure robust url handling in ldap.initialize without encoding parts of the url myself ? (which, I'm afraid, won't be that robust anyway).


Solution

  • One can use LDAPUrl.unparse() method to get a properly encoded version of the URI, like this :

    >>> import ldapurl
    >>> url = ldapurl.LDAPUrl('ldap://192.168.2.151/dc=directory,dc=example,dc=com')
    >>> url.unparse()
    'ldap://192.168.2.151/dc%3Ddirectory%2Cdc%3Dparalint%2Cdc%3Dcom???'
    >>> ldap.initialize(url.unparse())
    <ldap.ldapobject.SimpleLDAPObject instance at 0x103d998>
    

    And LDAPUrl.unparse() will not reencode an already encoded url :

    >>> url = ldapurl.LDAPUrl('ldap://example.com/dc%3Dusers%2Cdc%3Dexample%2Cdc%3Dcom%2F???')
    >>> url.unparse()
    'ldap://example.com/dc%3Dusers%2Cdc%3Dexample%2Cdc%3Dcom%2F???'
    

    So you can use it blindly on any ldap uri your program must handle.