A LDAP-enabled Zope 2 user folder
NOTE: Do not install the CMFLDAP GenericSetup extension profile into a Plone
site. They are meant for pure CMF sites only and will break Plone.
This product is a replacement for a Zope user folder. It does not store its
own user objects but builds them on the fly after authenticating a user against
the LDAP database.
Upgrading entails not only unpacking the new code, you should also delete and
recreate all LDAPUserFolder instances in your Zope installation to prevent
errors. A safe upgrade strategy looks like this:
- log in as an emergency user
- delete all LDAPUserFolder instances
- upgrade the filesystem product
- restart Zope
- log in as emergency user
- recreate the LDAPUserFolder instances
How to create an emergency user is described in the SECURITY.txt document in
the 'doc' folder at the root of your Zope software installation. The
mentioned 'zpasswd.py' script resides in the 'bin' folder at the root of your
All log messages are sent to the standard Zope event log 'event.log'. In
order to see more verbose logging output you need to increase the log level
in your Zope instance's zope.conf. See the 'eventlog' directive. Setting
the 'level' key to 'debug' will maximize log output and may help pinpoint
problems during setup and testing.
According to feedback received from people who use Netscape directory
products the way a new group is instantiated allows empty groups to exist
in the system. However, according to the canonical definition for group
records groups must always have a group member attribute.
The LDAPUserFolder looks up group records by looking for group member
entries. If a group record has no members then it will be skipped. As said
above, this only seems to affect Netscape directory servers.
To work around this (Netscape) phenomenon add one or more members to the
group in question using the tools that came with the directory server. It
should appear in the LDAPUserFolder after that.
LDAP as a source of Zope user records is an excellent choice in many cases,
- You already have an existing LDAP setup that might store company employee
data and you do not want to duplicate any data into a Zope user folder
- You want to make the same user database available to other applications
like mail, address book clients, operating system authenticators
(PAM-LDAP) or other network services that allow authentication against
- You have several Zope installations that need to share user records or a
- You want to be able to store more than just user name and password in your
Zope user folder
- You want to manipulate user data outside of Zope
... the list continues.
Your LDAP server should contain records that can be used as user
records. Any object types like person, organizationalPerson,
or inetOrgPerson and any derivatives thereof should work. Records
of type posixAccount should work correctly as well.
The LDAPUserFolder expects your user records to have at least the
following attributes, most of which are required for the
abovementioned object classes, anyway:
- an attribute to hold the user ID (like cn, uid, etc)
- userPassword (the password field)
- whatever attribute you choose as the username attribute
- typcial person-related attributes like sn (last name),
givenName (first name), uid or mail (email address) will make
working with the LDAPUserFolder nicer
Zope users have certain roles associated with them, these roles
determine what permissions the user have. For the LDAPUserFolder,
role information can be expressed through membership in group
records in LDAP.
Group records can be of any object type that accepts multiple
attributes of type "uniqueMember" or "member" and that has a
"cn" attribute. One such type is "groupOfUniqueNames". The cn
describes the group / role name while the member attributes point
back to all those user records that are part of this group. Only
those group-style records that use full DNs for its members
are supported, which excludes classes like posixGroup.
For examples of valid group- and user-records for LDAP please
see the file SAMPLE_RECORDS.txt in this distribution. It has
samples for a user- and a group record in LDIF format.
It is outside of the scope of this documentation to describe the
different object classes and attributes in detail, please see
LDAP documentation for a better treatment.
Since a user folder is one of these items that can lock users out
of your site if they break I suggest testing the settings in some
inconspicuous location before replacing a site's main acl_users folder
with a LDAPUserFolder.
As a last resort you will always be able to log in and make changes
as the superuser (or in newer Zope releases called "emergency user")
who, as an added bonus, can delete and create user folders. This is
a breach of the standard "the superuser cannot create / own anything"
policy, but can save your skin in so many ways.
The CMF (and by extension, Plone) expect that every user has an email
address. In order to make everything work correctly your LDAP user
records must have a "mail" attribute, and this attribute must be set
up in the "LDAP Schema" tab of your LDAPUserFolder. When you add the
"mail" schema item make sure you set the "Map to Name" field to
The attributes that show up on the join form and the personalize view
are governed by the properties you 'register' using the
'Member Properties' tab in the portal_memberdata tool ZMI view, which
in turn is sourced from the 'LDAP Schema' tab in the LDAPUserFolder
ZMI view. Attributes you would like to enable for portal members
must be set up on the LDAPUserFolder 'LDAP Schema' tab first, and
then registered using the 'Membeer properties' screen in the
Member data tool ZMI view.
- xxx [Jens Vagelpohl and contributors]
- added Trove classifiers
- SYSTEMSINTERNAL-370, SYSTEMSINTERNAL-371, SYSTEMSINTERNAL-372,
SYSTEMSINTERNAL-373: prepared product for being open sourced [Raj Shah]
- Bug/LDAPDelegate: Use the canonical explode_dn method when splitting
up a DN for escaping its values instead of hand-splitting on ",", which
breaks if the DN contains commas in any value. Patch by Russell Sim. This
also required cleaning up one test that used an invalid DN format.
- Factoring: For testing, use the fakeldap module from the
dataflake.ldapconnection package instead of maintaining a copy here.
- Factoring: Refactored unit tests to use ZopeTestCase and ZopeLite instead
of hand-rolling ZODB connections etc.
- Bug: Added explicit CMFDefault dependency for the CMF-related functions by
adding an extras_require in setup.py.
- Bug: Make sure a user is purged from the negative cache when the user is
explicitly expired. (http://www.dataflake.org/tracker/issue_00617)
- Feature: The site administrator may now set an arbitrary LDAP search filter
expression that will be applied to all user searches in addition to the
default filters. Only those user records matching both the default filter
and this arbitrary filter expression will be returned. CAUTION: The filter
expression must conform to standard LDAP filter syntax. Setting a wrong
value will lock out your users!
- Factoring: Move the LDAP server configuration off the Configure tab in the
ZMI to its own LDAP Servers tab to avoid overcrowding the configuration
view even more.
- Bug: The unit tests for the LDAPMemberDataTool and the LDAPMembershipTool
did not run due to a faulty import.
- Bug: The ZMI Caches tab erroneously suggested that a cached user's last
access time would be recorded and/or updated. This was not the case, it is
recorded at user object creation and then never updated. The Caches tab
will now reflect the creation time. Since the API to set or query the last
access time was not used anywhere it has been removed. (in response to
http://www.dataflake.org/tracker/issue_00614 by Stefan Loidl)
- Bug: Recreating the internal cache hash key inside
LDAPUserFolder.__setstate__ can lead to values differring from one thread
to the next, leading to unnecessary extra LDAP lookups for values already
cached under the original key.
(http://www.dataflake.org/tracker/issue_00608 by Stefan Loidl)
- Factoring: LDAPUserFolder.__setstate__: Removed old backwards-compatibility
- Bug: FakeLDAP could not handle BASE-scoped searches
- Bug: LDAPUserFolder.searchUsers mishandled searches on DN by not passing
the correct BASE search scope through. Found by Nico Grubert.
- Bug: LDAPUserFolder.getUserByAttr: The negative login cache used for
preventing repeated LDAP requests when a user enters wrong creadentials was
keyed on user login alone. This would prevent subsequent logins with the
correct password. Thanks to Tarek Ziade for test and patch and Gilles
Lenfant for filing the issue.
- Refactoring: test suite: Rearrange imports to prevent error messages when
the CMF is not present.
- Bug: LDAPDelegate.search: Improve searches on binary attributes such as
objectGUID by introducing a method argument that prevents UTF*-conversion
of the filter expression passed in.
(http://www.dataflake.org/tracker/issue_00576 by Wichert Akkerman)
- Feature: Improve binary attribute handlng by introducing a binary flag for
LDAP schema items that is consulted when inserting/modifying an attribute
flagged that way. Introduce a hardcoded list of binary attributes to no
convert from UTF-8 when searching.
(http://www.dataflake.org/tracker/issue_00598 Dragos Chirila)
- Bug: LDAPUserFolder.getUserByAttr: made login attribute and uid attribute
retrieval safer by explicitly providing a default.
(http://www.dataflake.org/tracker/issue_00602 by Martin Gfeller)
- Bug: ZMI Groups tab: Asking for the type of group via a separate LDAP
search for every group listed is unfeasible for installations with large
numbers of groups, it is now only done if the total number of groups is
less than 50.
- NOTE: In order to use the LDAP-based CMF membership components
you need CMF version 2.1.0 or higher.
- Bug: Added a __setstate__ hook for deleting old-style logger instances
which were removed for version 2.7 but are now showing up as "broken"
objects and may prevent Plone migration scripts from working correctly,
pointed out by Martijn Pieters.
- Bug: Removed failing unit test for old-style Zope 2 interfaces that no
longer exist in the CMF
- Bug: CMFLDAP skins: Cleanups and changes to align the custom skin scripts
and templates with their CMF 2.1.0 counterparts
- Bug: LDAPMemberDataTool: The "Member Properties" ZMI tab was broken due to
a typo in the ZPT code.
- Bug: LDAPMemberDataTool: Adjusted wrapUser to match the changed behavior in
CMF 2.1.0 and up.
- Bug: LDAPMembershipTool/LDAPMemberDataTool: Since the core CMF tools no
longer support the IActionProvider interface the tests to prove the
LDAP-based versions support these interfaces have been removed.
- Bug: The functional test rig setup has been changed to avoid
DeprecationWarning-Messages from GenericSetup 1.3 and up.
- Bug: LDAPUserFolder.searchGroups: Make the code more defensive for
situations where a search would return groups without members, suggested by
Nick Davis. (http://www.dataflake.org/tracker/issue_00584)
- Feature: Added negative caching for users to avoid querying the LDAP server
again and again for invalid logins. Patch provided by Wichert Akkerman.
- Feature: added a group/membership mapping for group type "univentionGroup"
- Documentation: Noted the danger of trying to install the CMFLDAP extensions
into a Plone site: Just don't do it, you will suffer!