Python-ldap notes

From Helpful
Jump to: navigation, search
This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

The py-ldap (a.k.a. python-ldap) package is one of a few that allow interaction with LDAP servers. It mostly wraps OpenLDAP 2.

Note that the below generally assumes synchronous interaction (function names end with _s). (Asynchronous communication is done by using exceptions as messages)


Options

It is often simple to set options globally (ldap.set_option()), to be used by everything, since the common case probably connects to just one LDAP server.

Alternatively, you can set options per connection (connref.set_option())


You probably want to avoid indefinite blocking:

ldap.set_option(ldap.OPT_NETWORK_TIMEOUT, seconds) 

For connections to work with LDAPv3, you want to:

connref.set_option(ldap.OPT_PROTOCOL_VERSION, ldap.VERSION3)

or (verify)

connref.protocol_version = ldap.VERSION3

You should do this after initialize and before any interaction.


ActiveDirectory is somewhat quirky, and you probably need:

ldap.set_option(ldap.OPT_REFERRALS, 0)

Connecting

The deprecated alternative is to use open(), handing in a host and port.

The now preferred way is to hand in LDAP URLs (see RFC 4516) like:

ldapurl = 'ldap://ldap1.exmaple.com'
ldapurl = 'ldaps://localhost:389'


Which you hand in to initialize:

connref = ldap.initialize( ldapurl )

Note that initialize does not connect yet - the first function that needs the connection does(verify), often bind or start_tls , but possibly later such as search (e.g. in case the server is an entirely public store of information).

SSL

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

You usually want a secure connection between LDAP client and server, unless you trust the network connection will never be snooped. Note that in many contexts, the connection between the LDAP code and the place the user types the password should also be secure, for the same reason. For example, in a web server context, you want SSL on the web-server-to-browser as well as the web-server-to-LDAP-server connection.

python-ldap supports TLS/SSL, apparently since 2.0.0pre06. (You want a version since then anyway, since LDAPv3 support was introduced about then) To test whether python-ldap was compiled with TLS support, look at the value of ldap.TLS_AVAIL.


One way to tell the module you want to use a secure connection is to hand in an ldap:// url and call start_tls_s() (after initialize(), and note this only works if you have already set VERSION3). This will raise an ldap.SERVER_DOWN exception if TLS fails.

Another way is to initialize using a https:// url. It seems you should then avoid calling start_tls_s().(verify)


Notes:

  • Hanging connections can be caused by trying non-secured connection on a secure-only port.

(i.e. using ldap: when you should use ldaps:)


TLS-related options mostly control the conditions for a connection. The default is to be strict, so these are not generally required.


For certificate verification, you want to point ldap.OPT_X_TLS_CERTFILE (TLS equivalent: TLS_CACERTFILE) to a file containing main/relevant certificates, or perhaps (TLS equivalent: TLS_CACERTDIR) (if you use it; if you haven't heard of c_rehash, you probably don't)


ldap.OPT_X_TLS_CERTFILE (TLS_CERTFILE) and ldap.OPT_X_TLS_KEYFILE (TLS_KEYFILE) are for client authentication (instead of the more usual server authentification). You can ignore them unless you want that.


The TLS equivalents of the following can be used in various areas:

  • OPT_X_TLS_NEVER
  • OPT_X_TLS_ALLOW
  • OPT_X_TLS_TRY
  • OPT_X_TLS_DEMAND
  • OPT_X_TLS_HARD
  • When you set them as if they were options and set them to 1:
    • OPT_X_TLS_TRY: Use TLS when available, but don't fail if it isn't.
    • OPT_X_TLS_DEMAND: Fail if TLS is not available


  • Also interesting is their use as values on ldap.OPT_X_TLS_REQUIRE_CERT (TLS equivalent: TLS_REQCERT)
    • demand and hard (default):
      • no certificate provided: quits
      • bad certificate provided: quits
    • try
      • no certificate provided: continues
      • bad certificate provided: quits
    • allow
      • no certificate provided: continues
      • bad certificate provided: continues
    • never
      • no certificate is requested

TODO: (verify); allow doesn't really make sense (though this comes from a man page, not the module docs).

Never is useful when a certificate cannot be authoritatively verified, e.g. in quick tests with self-signed test certificates. -->

Helpers

ldaphelper eases searching

Debugging

While debugging, the LDIFWriter may be convenient.

Also, you can see an on-screen trace by using

ldap.set_option(ldap.OPT_DEBUG_LEVEL,level)

(where level is e.g. 2 for basic details, or e.g. 255 for everything) may also be useful. Alternatively, use

trace_level=3, trace_file=sys.stderr)


Errors

This article/section is a stub — probably a pile of half-sorted notes, is not well-checked so may have incorrect bits. (Feel free to ignore, fix, or tell me)

ldap.LDAPError is based on a plain Python exception (has an args member).

Depending on the exception/error/message(verify), it may also have a dictionary member called message with keys 'desc' (describing the basic error/message) and 'info' (lower-level details).


There are a number of subclasses of LDAPError meant for asynchronous interaction.


A SERVER_DOWN in the context of SSL/TLS points to a failture to establish a secure connection.

A PROTOCOL_ERROR mentioning 'Unrecognized extended operation' points to the attempt to use a function that the server/protocol does not support.


See also

Tutorials: