Commentary by Mark Wahl, CISA
Organizing principles for identity systems:
Families of entries (20070719)
One of the X.500 features added for the 1997 revision is compound entries provided by families of entries, defined in section 8.11 of X.501(2005), and described on the X.500 pbwiki fan site x500standard.com in the page "X500/Families of Entries?". The compound entry concept provides X.500 directory servers with something similar to one of the virtual directory features: the ability to assemble a virtual 'view' in a single directory entry, in which the attributes of that view are made up of data from multiple sources. However, unlike a virtual directory,
- whereas a virtual directory pulls information from relational databases or multiple directories using transformation rules and mapping functions, the compound entry only pulls information from entries in the same directory server and those entries must be located in a single subtree,
- the 'view' is primarily of use for deleting and searching; directory client applications which add/modify/search entries need to be aware of the division of entries forming the compound entry, and
- no fancy transforms or joins are provided in X.500 compound entries: there needs to be at least one real directory entry backing each virtual entry, as each directory entry that is to be a compound entry is part of a "families of entries".
Nevertheless, families of entries are useful for modelling relationships between related attributes that make up a user's entry. For example, in a traditional X.500(88) or X.500(1993) directory, a user's entry might resemble
dn: uid=jbloggs, dc=example, dc=com
objectClass: top
objectClass: person
objectClass: inetOrgPerson
uid: jbloggs
telephoneNumber: 1 213 555 1212
telephoneNumber: 1 408 555 1212
postalAddress: 1 Foo Street $ San Jose, CA $ 94087 $ USA
postalAddress: 1 Bar Street $ Los Angeles, CA $ 90210 $ USA
In the above example, it is not possible to specify in X.500(88)/X.500(93) that the telephone number with the "1 213" prefix is associated with the "Los Angeles" address, and that the telephone number with the "1 408" prefix is associated with the "San Jose" address.
The problem gets worse when it is necessary to have multiple multi-valued attributes used by directory-enabled applications, as in
dn: uid=jbloggs, dc=example, dc=com
objectClass: top
objectClass: person
objectClass: inetOrgPerson
objectClass: mobileDeviceUser
uid: jbloggs
telephoneNumber: 1 213 555 1212
telephoneNumber: 1 408 555 1212
mobileTelephoneNumber: 1 213 555 9999
mobileTelephoneNumber: 1 408 555 9999
postalAddress: 1 Foo Street $ San Jose, CA $ 94087 $ USA
postalAddress: 1 Bar Street $ Los Angeles, CA $ 90210 $ USA
mobileDeviceCapabilities: <cameraphone/>
mobileDeviceCapabilities: <java/>
An application cannot tell which mobileTelephoneNumber is for a device with the cameraphone feature, and which has the java feature. LDAP/X.500 doesn't have any unique identifier for attribute values, and embedding the telephone number in the mobile device capabilities leads to duplication of data and problems for other applications which merely want the phone numbers of the user.
The approach taken in X.500(2005) to address this problem (while being protocol-backwards-compatible with existing X.500 clients) is families of entries, which are made up of a small subtree of entries, in which the entry at the top of the subtree is an ordinary entry that is termed the ancestor, and that ancestor entry is part of one or more families. A family is the ancestor entry plus a collection of one or more family member subtrees below it, in which the entries at the top of each family member subtree have the same most-structural-object-class. (As an entry can have only one most-structural-object-class, this means that an entry can be an ancestor entry with multiple families below it, but the only entries in common between two or more families is the ancestor entry itself). A family member is a subtree, in which the entry at the top of the subtree is immediately subordinate to an ancestor entry.
An ordinary entry is made into an ancestor when another entry is added below it, and the entry being added has the auxiliary object class child. When this occurs, the directory server automatically makes the entry immediately above that one become an ancestor entry by giving it the abstract object class parent. All of the entries in the subtree below an ancestor entry have the object class child. A strand is a hierarchy of entries from an ancestor down to a leaf family member entry.
For example, an entry with object class person might be an ancestor entry with two families: a location family and a personalComputingDevice family.
dn: uid=jbloggs, dc=example, dc=com
objectClass: top
objectClass: person
objectClass: inetOrgPerson
objectClass: mobileDeviceUser
objectClass: parent #automatically added by server as this entry has two families
uid: jbloggs
dn: cn=office-Northern, uid=jbloggs, dc=example, dc=com
objectClass: top
objectClass: location
objectClass: child #this entry is one family member of the location family jbloggs
cn: office-Northern
telephoneNumber: 1 408 555 1212
postalAddress: 1 Foo Street $ San Jose, CA $ 94087 $ USA
dn: cn=office-Southern, uid=jbloggs, dc=example, dc=com
objectClass: top
objectClass: location
objectClass: child #this entry is another family member of the location family of jbloggs
cn: office-Southern
telephoneNumber: 1 213 555 1212
postalAddress: 1 Bar Street $ Los Angeles, CA $ 90210 $ USA
dn: cn=mobilePhone-ATTWS, uid=jbloggs, dc=example, dc=com
objectClass: top
objectClass: personalComputingDevice
objectClass: child #this entry is one family member of the personalComputingDevice family of jbloggs
cn: mobilePhone-ATTWS
mobileTelephoneNumber: 1 213 555 9999
mobileDeviceCapabilities: <cameraphone/>
dn: cn=mobilePhone-Cingular, uid=jbloggs, dc=example, dc=com
objectClass: top
objectClass: personalComputingDevice
objectClass: child #this entry another family member of the personalComputingDevice family of jbloggs
cn: mobilePhone-Cingular
mobileTelephoneNumber: 1 408 555 9999
mobileDeviceCapabilities: <java/>
In the above LDIF, there are four strands:
- { uid=jbloggs,dc=example,dc=com
cn=office-Northern,uid=jbloggs,dc=example,dc=com } - { uid=jbloggs,dc=example,dc=com
cn=office-Southern,uid=jbloggs,dc=example,dc=com } - { uid=jbloggs,dc=example,dc=com
cn=mobilePhone-ATTWS,uid=jbloggs,dc=example,dc=com } - { uid=jbloggs,dc=example,dc=com
cn=mobilePhone-Cingular,uid=jbloggs,dc=example,dc=com }
The application can control what kind of virtual directory-like behavior it expects from the directory server with the FamilyGrouping argument on the Compare, Search and Remove (delete entry) requests.
The FamilyGrouping options applicable for removing entries are:
- entryOnly: Each entry is considered independently from all others, the child/parent relationships are ignored. This is the default for backwards compatibility with applications expecting traditional X.500 semantics. Deleting an ancestor entry would cause a notAllowedOnNonLeaf error, since a client can't delete an entry with subordinates.
- compoundEntry: Deleting an ancestor entry causes all subordinate child entries to be deleted as well.
Where it gets interesting is in search filter evaluation. The FamilyGrouping options applicable for comparing and searching are:
- entryOnly: Each entry is considered independently from all others: the child/parent relationships are ignored. This is the default for backwards compatibility with applications expecting traditional X.500 semantics.
- compoundEntry: The attributes from all family members appear to be grouped together into a single compound entry. When searching, if there are several attributes of the same type coming from different family member entries, all the values are merged together.
- strands: Each strand is considered independently, and all family member entries on a strand are merged together. If the merged attributes from the entries on a strand match the search filter, then that strand matches the search filter.
- multiStrand: A search based at the ancestor entry causes all combination of strands to be tested, and the compound entry matches the filter if at least one combination of strands matches the filter.
In the strands and multiStrand options, family member entries which have attributes that contribute to the match are called contributing members, and all of the entries on that strand are called participating members.
The client can control which entry's information it wants returned from the search with the familyReturn field of the entry information selection included in a Search request. The client can specify contributingEntriesOnly, participatingEntriesOnly, or compoundEntry, and optionally a set of object classes of families that should also be returned even if they didn't match.
Note that unlike a virtual directory, the entries from matching strands are returned as individual search result entries, rather than having their attributes combined into a single entry. So when compound entries are being used, directory applications would need to be aware of this division of entries and be prepared that matching an entry might result in a train of additional child entries with the attributes being returned. Compound-unaware applications might not work correctly.
For example, if a client searches for (&(uid=jbloggs)(telephoneNumber=1 213*)) with X.500(88) or X.500(1993) semantics (equivalent to the entryOnly FamilyGrouping and the contributingEntriesOnly familyReturn options), then the search would not match anything, as there is no entry with both those attributes.
If a client searches for (&(uid=jbloggs)(telephoneNumber=1 213*)) with the strands FamilyGrouping and the participatingEntriesOnly familyReturn, then the search would match the strands
- { uid=jbloggs,dc=example,dc=com [matches uid]
cn=office-Southern,uid=jbloggs,dc=example,dc=com [matches telephoneNumber] } - { uid=jbloggs,dc=example,dc=com [matches uid]
cn=mobilePhone-ATTWS,uid=jbloggs,dc=example,dc=com [matches mobileTelephoneNumber] }
and the client would receive the entries
- uid=jbloggs,dc=example,dc=com
- cn=office-Southern,uid=jbloggs,dc=example,dc=com
- cn=mobilePhone-ATTWS,uid=jbloggs,dc=example,dc=com
Annex C of X.511 provides examples of the use of families of entries.
David Chadwick proposed an Internet-Draft for adding familes of entries support as controls to the LDAP protocol, however this draft expired in 1999. It is archived.