[python-ldap] ldap.initialize() URLs must only contain scheme and hostport components: Commas break inside OpenLDAP
akkornel at stanford.edu
Wed Aug 16 01:53:29 EDT 2017
I have a documentation issue that I'd like to report, specific to `ldap.initialize()`, and the note regarding the URL parameter.
The documentation for pyldap says…
> Parameter uri has to be a valid LDAP URL.
But then, someone who is using my code (which uses pyldap) found an LDAP URL which was throwing a weird exception:
> Traceback (most recent call last):
> File "syncrepl-client", line 92, in <module>
> else SyncreplMode.REFRESH_ONLY
> File "/Users/akkornel/git/syncrepl/syncrepl_client/__init__.py", line 411, in __init__
> SimpleLDAPObject.__init__(self, safe_url.unparse(), **kwargs)
> File "/Users/akkornel/Library/Python/3.6/lib/python/site-packages/pyldap-2.4.37-py3.6-macosx-10.12-x86_64.egg/ldap/ldapobject.py", line 87, in __init__
> self._l = ldap.functions._ldap_function_call(ldap._ldap_module_lock,_ldap.initialize,uri)
> File "/Users/akkornel/Library/Python/3.6/lib/python/site-packages/pyldap-2.4.37-py3.6-macosx-10.12-x86_64.egg/ldap/functions.py", line 66, in _ldap_function_call
> result = func(*args,**kwargs)
> ldap.LDAPError: (2, 'No such file or directory')
I ended up tracing through pyldap, and then into OpenLDAP's code. Eventually, I found the problem: According to OpenLDAP documentation for the `ldap_initialize` function…
> The uri parameter may be a comma- or whitespace-separated list of URIs containing only the schema, the host, and the port fields.
So, you can pass `ldap_initialize` a "URL" like this:
… and OpenLDAP will accept it (if one URL doesn't work, try the next one, and so on).
This only got discovered because the LDAP URL which threw the exception was requesting multiple attributes. That meant the URL included an un-encoded comma, and the OpenLDAP library thought that was a URL separator.
I was wondering, would it be possible to change the pyldap documentation, to note the restriction on LDAP URLs?
Here's a diff of my proposed changes, for each application:
RCS file: /cvsroot/python-ldap/python-ldap/Doc/ldap.rst,v
retrieving revision 1.34
diff -u -r1.34 ldap.rst
--- Doc/ldap.rst 24 Jul 2016 16:12:55 -0000 1.34
+++ Doc/ldap.rst 16 Aug 2017 05:49:59 -0000
@@ -35,7 +35,8 @@
Initializes a new connection object for accessing the given LDAP server,
and return an LDAP object (see :ref:`ldap-objects`) used to perform operations
- on that server. Parameter *uri* has to be a valid LDAP URL.
+ on that server. Parameter *uri* has to be a valid LDAP URL containing
+ *only* the scheme and hostport components.
Note that the C wrapper function :py:func:_ldap.initialize() is called which calls
the OpenLDAP funtion ldap_initialize(). Calling this function just initializes
RCS file: /cvsroot/python-ldap/python-ldap/Lib/ldap/functions.py,v
retrieving revision 1.34
diff -u -r1.34 functions.py
--- Lib/ldap/functions.py 15 Aug 2017 16:21:58 -0000 1.34
+++ Lib/ldap/functions.py 16 Aug 2017 05:49:59 -0000
@@ -83,7 +83,7 @@
- LDAP URL containing at least connection scheme and hostport,
+ LDAP URL containing only the connection scheme and hostport,
If non-zero a trace output of LDAP calls is generated.
Another option would be to modify `ldap.initialize()` to accept any URL, and then pull out only the parts we want. But that seems like it wouldn't be worth it.
Please let me know if you have any questions about my request. Thanks very much!
~ A. Karl Kornel, (650) 736-9327
University IT, Stanford University
More information about the python-ldap