Choosing an entry’s RDN is something that shouldn’t be taken lightly. Ideally, it should meet all of the following criteria:
- It needs to be unique so that it doesn’t conflict with the RDNs of any other entries beneath the same parent.
- It should be something that’s not likely to change so that clients don’t have to worry about performing modify DN operations.
- It should be something that doesn’t contain any personally identifiable or otherwise sensitive information. DNs are often included in log messages, and if a client has permission to see any part of an entry, then they’ll be able to see its DN.
- It shouldn’t be something predictable. An attacker shouldn’t be able to guess the DN of a specific user, or even of any user in the server.
This means that things like usernames, common names, email addresses, and telephone numbers aren’t good choices. Account numbers are also not great because they tend to follow predictable patterns (e.g., sequentially increasing numbers).
What you really want is something that is basically random and has enough entropy to ensure that you won’t get an accidental conflict and so that an attacker will be unlikely to guess a valid value. It would be easy enough for a client to generate a long-ish random string to use for this purpose, but it turns out that the directory server (at least, a server that supports RFC 4530) already generates just such a value for each entry: its entryUUID.
Of course, there’s a catch-22 problem with using the entryUUID attribute as the naming attribute for an entry: the client doesn’t know what the entryUUID is going to be because it’s generated by the server. The client can’t specify it because the entryUUID attribute type is declared with the NO-USER-MODIFICATION constraint.
One potential workaround would be to create an entry with a throwaway value for the RDN, figure out what the entry’s entryUUID value is (using either the post-read control or by issuing a search to retrieve the entry), and issue a modify DN operation to rename the entry using that value. But that’s a hassle, and it puts undue burden on both the client and the server. Fortunately, if you’re using the Ping Identity Directory Server, then you have a couple of additional options:
- The client can include the “name with entryUUID” request control in the add request.
- The server can be configured so that any add request matching a specified set of criteria automatically gets created with entryUUID as its naming attribute.
Each of these will be described in more detail below.
The Name With entryUUID Request Control
The name with entryUUID request control may be included in an add request to indicate that the server should replace the RDN with the provided entry with one that uses the name and value of the entryUUID attribute the server generated for the entry. This control has an OID of “220.127.116.11.4.1.3018.104.22.168” and no value. We recommend that it be marked critical so that the add attempt will fail if the server cannot honor the request.
When using this control, the client should supply a DN for the entry that indicates the location in the DIT where the new entry should reside, but the RDN for the DN doesn’t really matter because it’s going to get replaced with the entryUUID. If you want, you can use an attribute value from the entry to add (just like if you were adding the entry without the control), but you can also use a bogus name-value pair. For example, you could provide a DN of “replaceWithEntryUUID=replaceWithEntryUUID,ou=People,dc=example,dc=com”, and the server would add the entry with a DN like “entryUUID=4869eea6-90bf-45bf-9fcb-eac096564bc8,ou=People,dc=example,dc=com” (although of course the entryUUID would vary each time).
Of course, there is one big issue with using this control: when the entry is added, the client won’t know what the entry’s actual DN really is. The way that we address that is to treat an add request that includes the name with entryUUID request control as if it also included a post-read request control with a single requested attribute of entryUUID. This will cause the add response to include a post-read response control with the DN and entryUUID value for the entry that was added. If you want additional attributes from the entry, you can explicitly include a post-read request control along with the name with entryUUID request control in the add request with the attributes you want to retrieve.
We provide support for the name with entryUUID request control in the ldapmodify command-line tool through the --nameWithEntryUIUD argument. For example:
$ bin/ldapmodify --hostname ds.example.com \ --port 636 \ --useSSL \ --bindDN "cn=Name With entryUUID Example,ou=Applications,dc=example,dc=com" \ --nameWithEntryUUID Enter the bind password: The server presented the following certificate chain: Subject: CN=ds.example.com,O=Ping Identity Self-Signed Certificate Valid From: Saturday, April 27, 2019 at 11:11:58 AM CDT Valid Until: Saturday, April 23, 2039 at 11:11:58 AM CDT SHA-1 Fingerprint: 41:5f:72:4a:e0:d0:22:18:3e:59:90:6f:65:fc:fe:34:f1:39:84:68 256-bit SHA-2 Fingerprint: 54:d5:58:07:bd:af:8b:b4:19:8e:03:a3:c5:14:0d:2a:e6:1e:c2:3a:29:6c:17:5f:5f:61:97:1d:31:3d:2b:ac WARNING: The certificate is self-signed. Do you wish to trust this certificate? Enter 'y' or 'n': y # Successfully connected to ds.example.com:636. dn: replaceWithEntryUUID=replaceWithEntryUUID,ou=People,dc=example,dc=com changetype: add objectClass: top objectClass: person objectClass: organizationalPerson objectClass: inetOrgPerson uid: test.user givenName: Test sn: User cn: Test User userPassword: testUserPassword # Adding entry # replaceWithEntryUUID=replaceWithEntryUUID,ou=People,dc=example,dc=com ... # Result Code: 0 (success) # Post-Read Response Control: # OID: 22.214.171.124.1.13.2 # Post-Read Entry: # dn: entryUUID=7866e6d4-faa7-40e4-bad0-9ef26e566efd,ou=People,dc=exa # mple,dc=com # entryUUID: 7866e6d4-faa7-40e4-bad0-9ef26e566efd
Since the control doesn’t have a value, it’s easy enough to use in any LDAP API that supports controls (although you may find it a chore to get the DN of the resulting entry if that API doesn’t also support the post-read response control). But if you’re using the UnboundID LDAP SDK for Java, we provide direct support for the control through the NameWithEntryUUIDRequestControl class. I’ve written a simple AddEntryNamedWithUUID program to demonstrate how to use this class to add an entry with the request control and get its DN.
Automatically Naming Entries With entryUUID
Although it’s pretty simple to use the control in an add request to explicitly indicate that an entry should use entryUUID as the naming attribute, this does require the client to know about and use the control. This isn’t always possible, but the Ping Identity Directory Server has you covered there as well. You can configure the server so that any add request that matches a specified set of criteria will automatically be treated as if it included the name with entryUUID request control. This option is available through the following pair of properties in the global configuration:
For example, if you wanted to configure the server so that any entry added with the “person” object class will behave as if it included the name with entryUUID request control, you would use a configuration like the following:
dsconfig create-request-criteria \ --criteria-name "Adds of Person Entries" \ --type simple \ --set operation-type:add \ --set "any-included-target-entry-filter:(objectClass=person)" dsconfig set-global-configuration-prop \ --set "auto-name-with-entry-uuid-request-criteria:Adds of Person Entries"
At this point, adding an entry with the “person” object class from any client will cause that entry’s RDN to be replaced with one generated based on the entryUUID operational attribute. The response will include the post-read response control as if the request had included the name with entryUUID request control (although the client will likely not know to look for it).