Hi,
currently, there are two LDAP stacks available for Plone: plone.app.ldap and
pas.plugins.ldap. Both stacks are using the defacto standard python-ldap library.
Issues with the current LDAP stacks
It is unclear under which license python-ldap is published.
The legal department of one of our customers has forbidden the use
of python-ldap in any of its companies projects.
Apart from the legal situation of the underlying library, both Plone LDAP
stacks have grown unnecessarily big and complex. Partly, this is due to
the lack of support of commonly needed features in python-ldap.
python-ldap is closely modelled after the C-API of OpenLDAP's libldap
and leaves handling of many common tasks to higher level libraries:
asynchronous calls, attribute name and type mapping from/to UTF-8,
connection pooling - to name just a few.
The lack of support in the defacto standard library leads to every
higher level LDAP-library either not supporting or reinventing those
common tasks more or less successfully.
Both Plone LDAP stacks have their own or at least different libraries
handling attribute name and type mapping and rely on a multitude of
other libraries to work. Both do not support asynchronous calls.
Searching for a user in Plone's sharing tab results in 1001 LDAP
requests for 1000 matches.
On top of that, pas.plugins.ldap needs to fetch all valid user ids for
each plone request.
Long-living caches mitigate the situation, but create problems
like users not appearing (depending on which frontend) or users still
being able to log-in despite being deleted hours ago.
Alternatives?
There is python3-ldap, an LDAP library written in pure Python, which
is also compatible with Python 2.
Given the heavy ASN-parsing involved in talking LDAP, we expect it to
be clearly slower than a C-based library.
Its API is confusing.
Recently, @datakurre revealed Asynchronous stream iterators and
experimental promises for Plone, which might help to greatly speed up
views involving LDAP-searches. In order to follow this idea we need
support for asynchronous LDAP calls.
Goal
Our goal is one LDAP request per sharing tab search and transparent
support of asynchronous calls where sensible, licensed under MIT/BSD
license.
Solution
We started development on a three-tier solution:
-
ldapy, a low-level pythonic library using libldap via cffi and
transparent support for asynchronous calls via generators. -
ldapalchemy, modelled after sqlalchemy to support session
management with connection pools and querying of LDAP entries with
attribute name and type mapping. -
pas.plugins.ldapalchemy, PAS plugin using ldapalchemy to
communicate with LDAP.
For uses cases where changing the full stack is not feasible we are
working on a drop-in replacement for python-ldap.
We would like to know whether you are sharing these concerns and what
you would like to see in such a new, slim stack with focus on
performance.
Initial funding was provided by a customer, the results of which are
published in ldapalchemy.
Currently, we are continuing without funding in our free time, but would
love to work on it full time, given the opportunity. If you have means to
support this effort, please let us know.