Groups setup in Cyrus IMAP

By default, Kolab ships with a configuration that lets Cyrus IMAP use LDAP roles as permission groups for IMAP folders. This article describes the configuration necessary to change a default Kolab deployment to use distribution groups instead of LDAP roles.

About Roles and Groups in LDAP

For as far as users and permissions are concerned, a role in LDAP is an object type attribute that is associated with the user’s entry directly. As such, they scale tremendously well. They are typically not used for email addresses, but for permissions.

The distribution groups we speak of are individual LDAP object entries where members are stored as a list in a multi-valued attribute. The following is an example entry for a distribution list for board members:

dn: cn=Board of Directors,ou=Groups,dc=example,dc=com
cn: Board of Directors
objectClass: top
objectClass: groupofuniquenames
uniqueMember: uid=john.doe,ou=People,dc=example,dc=com
uniqueMember: uid=jane.doe,ou=People,dc=example,dc=com

Groups come in different forms and shapes, and it is important to understand that ultimately, IMAP will require an attribute value of the group that adheres to valid syntax requirements. Therefore, the type of groups that IMAP can use as permission groups are limited to distribution groups only; these groups have an email address.

The uniqueMember attribute hold members of the group. In Kolab terminology this is a static distribution group, because members are defined statically, and new members need to be added manually. A different approach is a dynamic group. In this case members are defined as an LDAP filter, which is used every time a list of group members is needed. The same distribution group for board members would look as follows:

dn: cn=Board of Directors,ou=Groups,dc=example,dc=com
cn: Board of Directors
memberURL: ldap://localhost/ou=People,dc=example,dc=com??sub?(nsrole=board-member)
objectClass: top
objectClass: groupofurls
objectClass: kolabgroupofuniquenames

As you can see, the memberURL is the filter definition that describes where and how to find group individual members. Both these groups are traditional way of defining groups.


The other approach is to list groups the user is member of in user definition object. In other words user object holds information about which groups does the user belongs to. This is the opposite approach to traditional groups.

In 389 Directory server roles are defined in special attribute nsroledn. The value of that attribute should be a DN of defined role. Role definitions can be found with ldapsearch query filter "(|(objectclass=ldapsubentry)(objectclass=nsroledefinition))" and the example, Kolab adds a kolab-admin role by default, that has all of the day-to-day permissions necessary to add/modify/delete users, groups and so forth:

dn: cn=kolab-admin,dc=example,dc=com
objectClass: top
objectClass: ldapsubentry
objectClass: nsroledefinition
objectClass: nssimpleroledefinition
objectClass: nsmanagedroledefinition
description: Kolab Administrator
cn: kolab-admin

To list the roles a user is assigned to you need to query for nsrole attribute. That is a read-only special attribute, which is automatically created for a user after a valid nsroledn attribute is added. To query for nsrole or nsroledn attributes you need to specifically list these attributes as requested search result attributes because these are special attributes, and special attributes are not shown by a regular search of LDAP when not specifically requested.

Kolab and Groups

Kolab supports all types of LDAP groups, however a mail distribution group can be either static or dynamic traditional groups. If those distribution groups are to be used as permission groups, this does not align with default Cyrus IMAP ptloader configuration. The actual purpose of this article is to show how to reconfigure Cyrus IMAP to use the same traditional groups. This maybe be important when you need to set permissions for group when sharing a folder.

Kolab’s Default Cyrus IMAP Configuration

Kolab configures Cyrus IMAP with the following configuration snippet;

ldap_group_base: dc=example,dc=com
ldap_group_filter: (&(cn=%u)(objectclass=ldapsubentry)(objectclass=nsroledefinition))
ldap_group_scope: one
ldap_member_method: attribute
ldap_member_attribute: nsrole

This can be read as follows — using LDAP group method attribute look for nsrole attribute of the logged in user. The list of nsrole values is the groups the user belongs to. ldap_group_filter is used to get the list of available permission groups (roles).

Re-configure Cyrus IMAP

So to setup distribution groups as permission groups in Cyrus IMAP, change the following options in /etc/imapd.conf

ldap_group_base: ou=Groups,dc=example,dc=com
ldap_group_filter: (&(mail=%U)(objectclass=kolabgroupofuniquenames))
ldap_group_scope: one
ldap_member_base: ou=Groups,dc=example,dc=com
ldap_member_method: filter
ldap_member_attribute: uid
ldap_member_filter: uniqueMember=%D
ldap_size_limit: 0

A bit of explanation:

  • ldap_member_method – group type definitions. Allowed values are filter and attribute. To get static groups this attribute value must be set to filter.
  • ldap_member_base – This setting controls where to look for groups the user is member of.
  • ldap_member_attribute – that is a attribute which holds group identifier, a group name.
  • ldap_member_filter – attribute with instructions how to construct LDAP filter, group membership query filter.

These are the main 4 Cyrus IMAP configuration parameters controlling how to get group membership from LDAP.

In this particular case we have configured that Cyrus IMAP ptloader should use filter group membership query method and look for group membership under ldap_member_base: ou=Groups,dc=example,dc=com with the ldap filter ldap_member_filter: uniqueMember=%D.

For a user, this causes Cyrus IMAP to search for group membership with a filter of (uniquemember=uid=doe,ou=People,dc=example,dc=org).

Cyrus IMAP Group Membership Caches

This section re-iterates how to obtain, validate, review and expire the Cyrus IMAP group membership caches;

  • Examine the cache with /usr/lib/cyrus-imapd/ptdump,
  • Expire the cache with /usr/lib/cyrus-imapd/ptexpire -E0,
  • Login with a user that is a member of a distribution group that is used as a permission group, and examine the cache.

Some example output of ptdump;

user: cyrus-admin time: 1526972872 groups: 0
user: time: 1526972871 groups: 1

That is pretty self explanatory and it does represent the LDAP group definitions in Cyrus.

Now, when you need to share a specific folder to group, you can use a command similar to the following;

# kolab sam shared/ group:board read-write
Posted in Guides and tagged , , , , , .