In part 1 we’ve looked at how to install 389 Directory Server and create an instance. While this left us with a fully working LDAP server there are some plugins that greatly increase quality of life and might even be considered essential.
3. Plugins
3.1. Attribute Uniqueness
Certain attributes can have duplicate values within a directory. A simple example is a user’s first name which is stored in the givenName
attribute. In a directory with a sufficiently large number of users it’s more likely than not that there are two or more users with the same first name.
But how about a user’s email address? If the mail
attribute wasn’t unique within the whole directory this could lead to some trouble when delivering emails to a user’s inbox. Of course, a directory administrator might be careful when creating new users and ensure that each user has their own, unique email address. But humans make mistakes and checking manually if a certain email address is not already used is cumbersome at least.
The 389 directory server has a built-in plugin that can guarantee the uniqueness of attributes across the entire directory information tree (DIT) or even just certain subtrees. It can be conveniently configured and enabled through dsconf
.
Let’s say we wanted to guarantee that email addresses are unique across our whole dc=example,dc=com
tree, we would run:
dsconf localhost plugin attr-uniq add "mail attribute uniqueness" --attr-name mail --subtree "dc=example,dc=com" dsconf localhost plugin attr-uniq enable "mail attribute uniqueness"
Other very commonly unique attributes are a user’s ID (uid
), uid number (the integer uniquely identifying a user, uidNumber
) and gid number (the integer uniquely identifying a user’s primary group, gidNumber
). This is not a exhaustive list, of course, and which attributes are unique in a directory may very well depend on the use case. But together with the mail
attribute it’s probably a good starting point:
dsconf localhost plugin attr-uniq add "mail attribute uniqueness" --attr-name mail --subtree "dc=example,dc=com" dsconf localhost plugin attr-uniq add "uid attribute uniqueness" --attr-name uid --subtree "dc=example,dc=com" dsconf localhost plugin attr-uniq add "uidNumber attribute uniqueness" --attr-name uidNumber --subtree "dc=example,dc=com" dsconf localhost plugin attr-uniq add "gidNumber attribute uniqueness" --attr-name gidNumber --subtree "dc=example,dc=com" dsconf localhost plugin attr-uniq enable "mail attribute uniqueness" dsconf localhost plugin attr-uniq enable "uid attribute uniqueness" dsconf localhost plugin attr-uniq enable "uidNumber attribute uniqueness" dsconf localhost plugin attr-uniq enable "gidNumber attribute uniqueness"
The attr-uniq
plugin can also ensure uniqueness of values across multiple attributes. That’s called Multi Valued Uniqueness and is done by specifying multiple attribute names:
dsconf localhost plugin attr-uniq add "mail attribute uniqueness" --attr-name mail --attr-name mailAlternateAddress --subtree "dc=example,dc=com"
Note that the 389ds instance has to be restarted in order for the plugin to work (even though it was enabled through dsconf
:
dsctl localhost restart
3.2. Distributed Numeric Assignment
Similarly to manually checking for certain attributes to be unique it’s cumbersome to manually assign and manage uidNumber
and gidNumber
attributes. Fortunately this can be automatically handled by the Distributed Numeric Assignment (DNA) plugin.
The plugin settings can be configured through dsconf
again:
dsconf localhost plugin dna config "Account IDs" add \ --type gidNumber uidNumber \ --filter "(objectclass=posixAccount)" \ --scope ou=People,dc=example,dc=com \ --next-value 1001 \ --magic-regen -1
The parameters should be quite self-explanatory. Here’s a quick overview anyway:
-
--type gidNumber uidNumber
the DNA plugin should manage the attributesgidNumber
anduidNumber
(from the same range) -
--filter "(objectclass=posixAccount)"
it should be limited toposixAccount
objects -
--scope ou=People,dc=example,dc=com
only objects in the specified subtree should be managed -
--next-value 1001
the next value that’s going to be assigned -
--magic-regen -1
magic number to tell the DNA plugin that an object’sgidNumber
oruidNumber
should be automatically assigned
After enabling the plugin and restarting the 389ds instance
dsconf localhost plugin dna enable dsctl localhost restart
the DNA plugin will automatically reassign uidNumber
and gidNumber
attributes if they’re -1
# dsidm -b "dc=example,dc=com" localhost user create \ --uid eve \ --cn Eve \ --displayName Eve \ --homeDirectory "/home/eve" \ --uidNumber -1 \ --gidNumber -1 Successfully created eve # ldapsearch -LLL -x -b "dc=example,dc=com" "(uid=eve)" uidNumber gidNumber dn: uid=eve,ou=people,dc=example,dc=com uidNumber: 1001 gidNumber: 1001
You can, however, still specify uidNumber
or gidNumber
attributes manually by using a value that’s different from the configured magic number (-1
in the example above). The magic number itself is arbitrary and doesn’t need to be -1
at all.
For more details on the DNA plugin have a look at the Redhat Directory Server 11 (RHDS11) Administration Guide or the 389ds documentation, especially when using it in setups that use replication.
3.3. MemberOf
There are two ways how group membership of users can be stored. One can either save a list of members in each group object. That’s how it is done traditionally and is described in RFC2307:
Or one can store each group that a given user is a member of in the user object (RFC2307bis):
Querying an LDAP server that uses RFC2307 (sometimes also referred to as posix schema) if a certain user is authorised to access a particular resource is a two-step process: The first query searches for the user object (e.g. a user named Bob) and the second query checks if the user object’s uid
attribute matches one of the entries in the relevant group object (e.g. if the group blog_users has an attribute memberUID
that matches Bob’s uid).
A lot of software supports this, e.g. have a look at Grafana’s LDAP auth module. It has a search_filter
parameter that let’s you query for a particular user and an additional group_search_filter
parameter that filters out users that are not a member of a particular group.
However, that’s not always the case, e.g. postfix or dovecot do not have an additional group filter. The advantage of the RFC2307bis schema is (among other things) that checking user authorisation can be done in a single query, for example:
ldapsearch -LLL -x -b "dc=example,dc=com" \ "(&(uid=eve)(memberOf=cn=cncuser,ou=groups,dc=example,dc=com))" mail dn: uid=eve,ou=people,dc=example,dc=com mail: eve@example.com
389ds uses a combination of these two schemas so it stays compatible with both. The memberOf plugin can automatically update a user object’s memberOf
attributes whenever the group membership status is changed. Once again it can be enabled through dsctl
:
dsconf localhost plugin memberof enable dsctl localhost restart
Note that additonally group members will still be listed as multi-valued attributes in the group object (according to the RFC2307 schema). So you can decide depending on the user case wether to use the memberOf
filter or two queries to check if a user is authorised to access your resource.
3.4. Referential Integrity
In general, referential integrity is a property of arbitrary data structures (e.g. an object in OOP, a table in a relational database) meaning that all references to other data structures are vaild. In the context of a directory server it means that an update on one entry in the DIT is correctly reflected in all other entries that reference it.
This is most commonly an issue when removing a user or a group. When a user that’s a member of any group is removed, all corresponding member
attributes of the groups need to be updated as well. Managing this manually would be a nightmare, of course, so thankfully there’s a referential integrity plugin available that takes care of this:
dsconf localhost plugin referential-integrity enable dsctl localhost restart
That’s it regarding plugins. There are many more very useful ones available but these should cover the basics. The next part is going to look into ACLs.
Can you explain a little around how to activate rfc2307? Obviously I can enable memberOf plugin and I see the group DN is populated by member attributes (rfc2307bis). Accordingly memberOf attribute in user DN is populated. Nevertheless, the memberUid attributes in group DN remain always untouched – can’t they get synced automatically?!
I’m guessing RFC2307 isn’t exactly compatible with RFC2307bis. You use either, but not both. I’ve noticed that specifying «memberUid» as the group attribute, made MemberOf prevent 389ds from booting, due to MemberOf not liking the OID used for that field, that is neither a distinguished name nor another defined name OID. Thus, to make it work, you kind of have to adopt RFC2307bis. Then, your PosixGroup will have a «member» field, that is filled with the full distinguished name of the member object. From what I gather, SSSD deals cleanly with this. NSLCD needs configuration, but probably works fine, as well. Your mileage may vary, depending on the application you’re dealing with.
https://github.com/389ds/389-ds-base/issues/5968