We can use any distinguished name (DN) attribute syntax (126.96.36.199, 188.8.131.52, or 184.108.40.206) to specify the DN of another object in the directory as the value for the attribute. If the other object is moved or renamed, the DN in the attribute value is automatically updated with the change. Any attribute defined with one of the DN syntaxes will have this sort of behavior.
This type of syntax allows us to express a type of foreign-key relationship with any other object in the directory. As anyone who has modeled data for relational databases knows, foreign-key relationships are extremely powerful mechanisms for expressing relationships between entities. However, since DN syntax attributes can be either single- or multivalued, it is much easier to express many-to-many relationships in LDAP than it is in a relational database. As we discussed in Chapter 6, multivalued linked DN syntax attributes also do not have any explicit limitations on the number of members (although there are complications in retrieving all the attribute values if we exceed a certain threshold).
To illustrate this topic, let's create a hypothetical DN syntax attribute called People-Who-Rock (peopleWhoRock) that will exist as part of the user object. This will be a multivalued attribute containing the DN for each user object representing people whom we like (they rock!). As the user accounts represented in this attribute are moved or renamed in the directory, their DN is kept up-to-date in our attribute. The system does all of this automatically (like magic). However, if we were one of the lucky people specified in the attribute, wouldn't it be nice to know at a glance who else thinks we rock?
Link Value Pairs
LDAP also allows for the notion of link value paired attributes. Comprising a forward-link and back-link attribute pair, these DN syntax attributes are commonly used in both ADAM and Active Directory. A back link is another DN attribute that the directory calculates to show the opposite relationship to its forward link.
From our previous example, let's suppose we create another attribute called People-Who-Think-We-Rock (peopleWhoThinkWeRock) to serve as the back link for our peopleWhoRock forward link. These two attributes together will comprise a new link value pair. Every time we add another DN into our peopleWhoRock attribute, our own DN will be added automatically to the peopleWhoThinkWeRock attribute on our target DN's object. This way, we can see both sides of the relationship. In this case, it is a many-to-many relationship, where the back link tracks all the objects that refer to its containing object in its forward link. If this does not sound familiar yet, a more familiar example of this might be the member and memberOf linked attributes.
Since the directory maintains back links dynamically, they are never edited directly. Only forward links can be edited. Continuing with our hypothetical attribute, we can update the peopleWhoRock attribute, but we cannot change the peopleWhoThinkWeRock attribute on any object. That is, we can always specify whom we think rocks, but we cannot force others to recognize our own greatness (too bad!). Another implication of this is that if our own object is renamed or moved in the directory, a change will be recorded for our object, but the subsequent update to the peopleWhoThinkWeRock back-link attribute will not result in an actual modification for any other object.
We establish forward links and back links by setting the linkID attribute on the attributeSchema object during creation. The formula for calculation is very simple: A forward link is indicated by an even integer, and its matching back link will be that number plus one. As an example, in Active Directory, manager is linkID 42 and directReports is linkID 43. Forward links can be of the 220.127.116.11, 18.104.22.168, or 22.214.171.124 (DN-DN, DN-With-Binary, or DN-With-String) syntax, however back links must have the attribute syntax 126.96.36.199 (DN-DN) to use linking.
DN Syntax Attribute Best Practices
When designing DN attributes, we should consider a number of best practices that can potentially save us a lot of pain down the road.
Consider Using Linking for All DN Syntax Attributes
Even if we currently cannot think of a reason to establish a link value pair when creating a new DN attribute, doing so is still generally a good idea. When an object is deleted, it is moved to a special container for deleted objects so that replication partners can also be made aware of the deletion. These deleted objects are collectively referred to as tombstones. A tombstone's DN is updated to a special syntax and most of the attributes on the tombstone are removed. For instance, if we were to delete a user's account (named Alice) that we had previously specified in our peopleWhoRock attribute, the DN for the deleted user would look something like this:
CN=Alice DEL:2e17b192-cadc-4eb9-8415-da3d2886ba88, CN=Deleted Objects,DC=domain,DC=com
The first newline character after Alice is actually part of the DN itself, and the second one is there for formatting purposes only. Alice's user object is now a tombstone in the system that will be persisted for a period of time in the special Deleted Objects container until the system removes it.
Tombstones are treated very differently depending on whether a DN syntax attribute is part of a link value pair. If we had created only the peopleWhoRock attribute and we never create and link the peopleWhoThinkWeRock attribute, then our peopleWhoRock attribute will show Alice's tombstone's DN by default. We almost never want this behavior. If, however, we create and link both the peopleWhoRock and the peopleWhoThinkWeRock attributes, then when Alice's account is deleted, the DN will simply be cleared from the peopleWhoRock attribute, which is the behavior most developers would expect.
Warning: linkIDs Must Be Specified When the Schema Is Created
We learned this the hard way. If we fail to specify the linkID of an attribute when the schema is created, we have schema that does not behave the way we want and we cannot fix it. We must start over with new attributes (and possibly convert the existing data if this slips into production unnoticed). This is definitely something we will want to avoid.
This surprising behavior can lead to subtle bugs in applications (especially since we cannot read tombstone objects by default and they have almost no data in them), and it is usually not what we want.
Tip: Forward Links Do Not Require Back Links
If for some reason, we are dead-set against a back link, we can still specify the linkID value for the forward-link attribute and get the other benefits of link value attributes, even though no back-link attribute exists. The behavior does not appear to be documented, but it is supported.
Another feature of linked attributes is that linked multivalued attributes actually behave differently than normal multivalued attributes. In Chapter 6, we discussed enumerating the values of large attributes and mentioned that only linked attributes can have an effectively unlimited size. Regular DN attributes are subject to the size limits that the directory imposes on normal multivalued attributes.
Back Links Are Multivalued and Are Added to the Top Class
When we design an attribute to be a back link to another DN-syntax attribute, it should always be multivalued and it should be added to the top class. If we think about it, this makes perfect sense, for several reasons.
Register linkIDs or Use Auto linkID Generation
The syntax for linkIDs is just a positive integer, as opposed to an OID or a GUID. These linkIDs also have to be unique in the directory, yet obviously, it is much easier to produce collisions with them. As we explained earlier, Microsoft offers a service to register an OID for your organization to use, and it also offers a service to register linkIDs for use within Active Directory. Use this! Do not randomly invent linkID values for use in the directory. Let's reinforce this point by way of a true story (the name has been changed to protect the innocent).
An Active Directory administratorwe will call him Stevebought a vendor product that required a schema extension to Active Directory. This schema extension also introduced several link value attributes. The product installed well and Steve was very happy with its performance. Fast-forward two years: Now Steve wants to install the schema extensions required for Microsoft's flagship email system, Exchange Server 2003. He runs the installer but gets an error that stops him flat. It seems that the linkIDs Exchange Server 2003 wants to use for its schema are already in use! Steve contacts Microsoft technical support and discovers that his other vendor has used linkID values that Microsoft already registered (correctly) for use with Exchange Server 2003. However, the vendor's schema is already in the directory, preventing Steve from installing the system. So to work around the problem, Microsoft has to create a customized version of the Exchange Server 2003 schema that will install on Steve's directory. As we might imagine, it took a fair amount of time and effort for everyone involved to resolve the issue, and it threw Steve's upgrade plans into a tailspin for a month or so.
The lesson here is that if everyone plays by the rules, no one gets hurt. It's simply too easy to create collisions with linkIDs to allow any laziness. We should always register any linkIDs we create.
One other option is available to us in Windows 2003 Active Directory and ADAM. These directories support a feature called auto link IDs. Instead of hardcoding linkID values, we can specify a special OID value for the forward link, 1.2.840.1135188.8.131.52, and specify the ldapDisplayName attribute value of the forward-link attribute for the back link's linkID attribute. Eric Fleischman provides more details on this littleknown feature in his blog.
Search Flags and Indexing
Part I: Fundamentals
Introduction to LDAP and Active Directory
Introduction to .NET Directory Services Programming
Binding and CRUD Operations with DirectoryEntry
Searching with the DirectorySearcher
Advanced LDAP Searches
Reading and Writing LDAP Attributes
Active Directory and ADAM Schema
Security in Directory Services Programming
Introduction to the ActiveDirectory Namespace
Part II: Practical Applications
Part III: Appendixes
Appendix A. Three Approaches to COM Interop with ADSI
Appendix B. LDAP Tools for Programmers
Appendix C. Troubleshooting and Help