GRUF 3 NOTES WITH LDAPUserFolder

Overview

LDAP support was not perfect with GRUF < 3. It worked perfectly in a read-only, non-groups situation, but setting groups inside LDAP was a pain (you had to put two LDAPUserFolder objects, one for users, the other one for groups) and it was not possible to nest groups nor to set specific roles on groups.

GRUF 3.0 solves part of this problem - and it's not been easy ! This document explains how GRUF 3 handles LDAPUserFolder sources. More generally, this document explains how to have Plone + GRUF + LDAPUserFolder and beeing happy.

Operation

Introduction

An LDAP directory is not a very simple thing to use. You need to have a basic knowledge of how it works before going any further. Especially, you have to precisely know what is:

  • A key
  • A class
  • A schema
  • An attribute / a value
  • A multivalued attribute
  • A DN, a RDN

Warning

If you don't master any of those LDAP concepts, just forget about plugging LDAP into Plone and go to further readings about LDAP.

Your LDAP database and Zope

Now you've got to think about what you plan to do with your LDAP directory.

Read-only versus Read-write

If you want to set a read-only access from Zope, you don't have to read this section.

If you want to allow Zope to write into your LDAP directory, things get more complicated... A lot of issues is involved, essentially because LDAPUserFolder is NOT (and is not intended to be) an LDAP directory management tool.

Those issues are out of scope of this document.

Groups and roles storage

At one point, you have to decide if you want your Zope roles and groups stored in your LDAP directory or in your ZODB. You have to make a clear choice here - it's not possible to have some groups or roles in LDAP and some of them in ZODB.

If you decide to store your groups in LDAP, it won't be possible to give Zope roles to those groups.

If you decide to store your groups in LDAP, it won't be possible to have nested groups.

Groups creation by LDAPUserFolder is not covered by this document.

LDAPUserFolder requirements

Users

By default, LDAPUserFolder expects your user class to have the following structure:

(root) o=Organization, c=US
|
|-- ou=people
    |
    |-- cn=User1's name
    |     cn: User1's name
    |     objectClass: top, person
   ...

You can easily change some of these parameters in LDAPUserFolder configuration. Especially, you can configure the attributes used to fetch or name users:

  • Login name attribute: (Zope side) That's the attribute used to determine the login name (ie. the name the user types-in to identify himself when he is prompted to do so in Zope or Plone).
  • userid attribute: (Zope side) That's the attribute used to handle the user's id everywhere EXCEPT for the login. This is not currently supported by Plone.
  • rdn attribute: (LDAP side) That's the attribute used as the rdn (it's easy !). This is used only with read-write directories, to create new entries in the database.

Ok. Now, the rest is just a matter of tuning things in. It will enventually work, as this is the simplest case - if you cannot manage to make this part work, don't even go further in this document :^)

Warning

Once again: you _need_ basic LDAP knowledge and basic Zope knowledge to make this work. Don't do things if you don't understand them!

Groups in LDAP

LDAP interaction is an easy thing until you want to manage your groups in LDAP. That's where the things get complicated because there are several options and many elements in the chain to handle this properly.

If you don't want groups to be managed by your LDAP directory, skip this part and go to the "No groups" section below.

First of all, you MUST set "groups stored on LDAP server" in LDAPUF configuration to have your groups stored in LDAP.

LDAP Groups function differently with or without GRUF. Without GRUF, LDAP groups are mapped to Zope ROLES. With GRUF, well... it depends :-) (this is explained below)

But in any case, you groups schema must conform to something like this:

(root) o=Organization, c=US
|
|-- ou=people
|   |
|   |-- cn=User1's name
|   |     cn: User1's name
|   |     objectClass: top, person
/  ...
|
|-- ou=groups
    |
    |-- cn=Group's name
    |    cn: Group's name
    |    objectClass: groupOfNames
    |    member: cn=User1's name, ou=people, o=Organization, c=US
   ...

When reading groups, they can belong to one of the following classes : "groupOfUniqueNames", "groupOfNames", "accessGroup" or "group". Depending on that class, the attribute holding group members changes. Here's the mapping, as defined is LDAPUserFolder.utils:

GROUP_MEMBER_MAP = {
                   'groupOfUniqueNames' : 'uniqueMember'
                 , 'groupOfNames' : 'member'
                 , 'accessGroup' : 'member'
                 , 'group' : 'member'
                 }

Important

This shema implies a very important thing: user/group mapping is stored on the group key and not on the user key. This is something you must keep in mind while managing your LDAP directory.

Groups in ZODB

If you don't want your groups to be stored on the LDAP server, just set "Groups NOT stored on LDAP server" in the "Configuration" tab of LDAPUserFolder.

GRUF binding

Once you're happy with your LDAP structure, and once you've tested your configuration with LDAPUF alone (id est in an empty folder, without GRUF), you can proceed with GRUF.

Groups in LDAP

If you want your roles and groups stored in LDAP, you have to know the following facts:

  • You have to set "Groups stored on LDAP server" in LDAPUF's configuration.

  • Your groups structure in LDAP must conform to what is explained below (ie. you must use groupOfNames-like classes and cannot use posixGroups).

  • If you want to set a specific role (Manager, Reviewer, ...) on a specific LDAP user, you must have the following two conditions fulfilled:

    • The role you want to set must be mapped, in LDAPUserFolder, to a LDAP Group.
    • Your LDAPUF's configured manager DN must have the right to modify this group key.
  • Local roles work normally - setting a local role doesn't require to write something in LDAP.

  • GRUF Groups have the same requirements as Zope roles plus a few others : if you want to put a user in a group, you have to care about this:

    • The GRUF group you want to set must be mapped, in LDAPUserFolder, to a LDAP Group. You can do this either:

      • manually in LDAPUserFolder (in the "Groups" tab)
      • by clicking the "Update" button located at the bottom of the "Sources" tab in GRUF 3.2.
    • Your LDAPUF's configured manager DN must have the right to modify this group key.

    • You need to use LDAPGroupFolder (provided with GRUF >3) as a Groups Source in GRUF.

Groups in ZODB

If you want your groups to be stored in ZODB, things are much easier:

  • You have to set "Groups NOT stored on LDAP server" in LDAPUF's configuration.
  • LDAP User - Zope role mapping is done by LDAPUserFolder, as expected.
  • You MUST NOT use LDAPGroupFolder as a groups source. Use the regular groups source instead.
  • You must map GRUF groups to Zope roles in LDAPUserFolder. You can do this either:
    • manually in LDAPUserFolder (in the "Groups" tab)
    • by clicking the "Update" button located at the bottom of the "Sources" tab in GRUF 3.2.

Plone binding

The simplest case

To have Plone work with the above configuration, it's quite simple... Just do it ! ;) It's easy with Plone 2.0.5.

All your site members should have the 'Member' role in Plone. So you have to replace, in LDAPUF's configuration page, the 'Anonymous' default role by 'Member'.

Then, drop an empty file called preview.txt in your GroupUserFolder's directory, and restart Zope. This will enable some Plone bugfixes and patches to make it work better.

...However, some Plonish stuff won't work out-of-the-box. Here's a list of known issues.

User creation / mutation

Joining a user won't work if your directory is read-only. You'd better disable this - anyway it's a bad idea to allow direct LDAP manipulation through a link on the web!

For the same reason, some forms in the users management configlet may fail. You'd rather operate in ZMI instead.

Then, you'll notice that individual user preferences page NEVER saves data back in the LDAP server. It's a normal a known behaviour - to disallow, for example, people from modifying their LDAP-stored email address.

Email and other assorted information

To have the ability to see people's email, you just have to do a mapping in LDAPUserFolder, with the schema configuration page.

Plone's attribute for email is... "email".

So, if your users are stored as inetOrgPerson classes, here's the mapping you can do:

LDAP name Mapped to name
displayName fullname
mail email
jpegPhoto portrait

Yes, the JPEG photo will work - at least with GRUF 3.2.

Password retreiving

As passwords are stored crypted (and often unreadable) in LDAP, you cannot allow people to retreive their password by email.

Local roles management

Local role work fine with the preview.txt hint: the localroles form is able to retreive LDAP users which are not in LDAPUF's cache (people who already had this problem will know what I mean!).

However, there's a bug in folder_localroles_form which prevents assigning a local role to a group in GRUF 3.2 + Plone 2.0.x. You have to fix this template like this:

405c405
<                         <td tal:define="global group_name group/getUserId">
---
>                         <td tal:define="global group_name group/getUserName">

A version is provided (but not installed) in the gruf_plone_2_0 directory of GRUF.

Issues and tips

Encoding

The encoding used to return LDAP values to Zope is Latin 1. Ie., even if your LDAP directory manages UTF8 perfectly, you are bound to Latin1 encoding in your Zope application (unless you edit LDAPUserFolder.utils.encoding).

User creation and mutation

With GRUF 2, it was not possible to create or change a user. It's now possible to change a user quite easily. This is not covered in this document.

Mutation is quite transparent, however creation is more complex. Here's a hint on this:

All user keys must have a fillable cn, uid and sn attribute. This is right for inetOrgPerson stuff. This is required because at creation time we only know user's login (not his name nor other information). So we fill those three required fields with his login. This behaviour can be changed by customizing the gruf_ldap_required_fields script (within Plone only).

Groups support info

GRUF 3 now supports groups natively with different strategies. You have to choose which strategy to use depending on where your groups are stored (in your LDAP database or not).

Whatever you choose, you can always create groups through GRUF. Remember that some group assigning may need you to have the proper rights to edit your LDAP database.

LDAP Groups

If you want to store your groups in LDAP, you have to understand a few things.

First of all, LDAP supports groups and not roles. Zope natively supports roles and not groups. So what LDAPUF (alone) does is basically mapping LDAP groups to Zope roles.

[BTW, you cannot assign a role to a user if that role doesn't already exist in LDAP, even if you map, in LDAPUF, a group to that particular role.]

This is okay for the common usage but with GRUF, as groups now appear within Zope, it gets more complicated. A LDAP group can be seen either as a role or a group within Zope. We decide that with the following assertion:

If a LDAP group has the same name as a Zope role, then it's seen as a role. It's seen
as a group in any other case.

Within GRUF, you've got a new user source which is called LDAPGroupFolder. Just drop it in place of your existing group source, AFTER you've instanciated your LDAPUF.

Implementation

To achieve such a result, we've been obligated to hotfix LDAPUF. Please be aware that we NEVER modify a method, we just add new ones.

We integrated this product : http://zope.org/Members/volkerw/LDAPUserFolderExt/LDAPUSerFolder_0_4 So... it's not compatible anymore with GRUF 3 ! :-)

Warning: LDAPUF may cause some additional roles having the same name as groups to appear in some GRUF pages. This is due to http://www.dataflake.org/tracker/issue_00376 issue.

Compatible LDAPUF versions

System Message: WARNING/2 (doc/README-LDAP.rst, line 379)

Title underline too short.

Compatible LDAPUF versions
-----------------------

By now, only LDAPUF >= 2.4Beta3 has been tested successfuly. I personnally recommand LDAPUserFolder 2.5.