[python-ldap] Validated URL can't be used for bind - handling SRV lookups

Elias Probst mail at eliasprobst.eu
Wed Oct 16 00:33:31 CEST 2013


Hi list,

I'm working on improvements to the LDAP authentication module for 'Salt'
(Saltstack):
https://github.com/saltstack/salt/blob/develop/salt/auth/ldap.py

I planned to make it possible to use URLs like this:
ldap:///dc=company,dc=tld

When using such an URL on the commandline (e.g. ldapsearch) this will
cause a DNS lookup to retrieve SRV records from DNS contining pointers
to LDAP hosts and their ports which will then be used to bind to.

python-ldap validates such an URL just fine using ldapurl.isLDAPUrl(),
but actually using in in ldap.initialize() will fail. Below is some
output and  test code:

-->snip - Output<--
Valid: ldap:///dc=institution,dc=de
initialize() failed: ldap:///dc=institution,dc=de - (2, 'No such file or
directory')

Valid: ldap:///dc%3Dinstitution%2Cdc%3Dde
initialize() succeeded: ldap:///dc%3Dinstitution%2Cdc%3Dde
bind failed: {'desc': "Can't contact LDAP server"}

Valid: ldap://u-dc01.institution.de:389
initialize() succeeded: ldap://u-dc01.institution.de:389
bind succeeded
-->snap - Output<--

-->snip - Code<--
#!/usr/bin/python

import ldap
import ldapurl

urldict = {
    'ldap://u-dc01.institution.de:389',
    'ldap:///dc=institution,dc=de',
    'ldap:///dc%3Dinstitution%2Cdc%3Dde',
}

binddn='user at institution.de'
bindpw='somepassword'

for url in urldict:
    # validate
    if ldapurl.isLDAPUrl(url):
        print 'Valid: {0}'.format(url)
    else:
        print 'Invalid: {0}'.format(url)

    # initialize
    try:
        l = ldap.initialize(url)
    except ldap.LDAPError as ldaperror:
        print 'initialize() failed: {0} - {1}'.format(url, ldaperror)
    else:
        print 'initialize() succeeded: {0}'.format(url)

        # bind
        try:
            l.simple_bind_s(binddn, bindpw)
        except ldap.LDAPError as ldaperror:
            print 'bind failed: {0}'.format(ldaperror)
        else:
            print 'bind succeeded'


    print ""
-->snap - Code<--

This seems to happen, because python-ldap doesn't use dn2domain() and
domain2hostlist() from libldap. See also the following IRC log where
OpenLDAP dev 'hyc' pointed me towards this:

-->snip - IRC-Log<--
<eliasp> I'm using python-ldap but it seems to be unable to do SRV
lookups when using an URI like ldap:///dc=company,dc=tld although it
validates the URI just fine using ldapurl.isLDAPUrl()
<eliasp> does anyone know whether there are known issues with
python-ldap and doing SRV lookups?
<eliasp> a manual 'ldapsearch' using this URI works just fine, so it
doesn't seem to be an issue with my OpenLDAP libs but actually an issue
of python-ldap itself… ;-(
<hyc> dunno anything about how python-ldap works
<hyc> seems like you need a python-specific channel, not #openldap
<eliasp> ok, ldapsearch actually just takes the URLencoded
representation of said URI, but even this one doesn't work in python-ldap…
<eliasp> hyc: yes, maybe…
<hyc> is python-ldap pure python?
<hyc> or does it just use libldap underneath?
<JoBbZ> hyc: when I looked at it, it linked to libldap
<eliasp> hyc: it uses libldap
<eliasp> hyc: from the python-ldap README: "[…] Mainly it wraps the
OpenLDAP client libs for that purpose."
<hyc> eliasp: ok. should note, libldap doesn't do SRV processing.
<hyc> the OpenLDAP cmdline tools do it themselves
<eliasp> hyc: meh, ok… that explains a lot ;)
<hyc> since the behavior is not part of the C API spec, we didn't move
it into there
<eliasp> hyc: any chance on doing this in libldap at some point?
<eliasp> ok
<hyc> it would be a major behavior change, I think no.
<hyc> currently ldap:/// always means localhost. lots of things would
break if it turned into an automatic DNS lookup
<eliasp> so there's actually no way to make use of SRV records outside
the cli tools (besides manually decomposing the URI and doing a manual
SRV lookup based on the URI structure)?
<hyc> pretty much
<eliasp> hyc: hmm, ok… well, looks like I got to spend some more hours
on implementing this then in my module… :)
<eliasp> hyc: anyways, thanks a lot for the information
<hyc> eliasp: at least you can look at the code in openldap
clients/tools as a model
<eliasp> hyc: I definitely will…
<hyc> the bits you need are implemented in libldap, e.g. ldap_dn2domain
and ldap_domain2hostlist
<hyc> so it shouldn't be too tough
<eliasp> hyc: ok, looking at it now
-->snap - IRC-Log<--


So I'm wondering whether it would be possible to add support for doing
this in python-ldap by using the said functions in libldap?
Otherwise I think such URLs shouldn't be validated successfully, as they
obviously can't be used to bind.

Best regards and thanks a lot for all the work on python-ldap!
- Elias P.

P.S. Using:
- Python 2.7.5
- python-ldap-2.4.13
- openldap-2.4.35
- Binding to ActiveDirectory (2008)

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 263 bytes
Desc: OpenPGP digital signature
URL: <http://mail.python.org/pipermail/python-ldap/attachments/20131016/0390e9dc/attachment.sig>


More information about the python-ldap mailing list