This set of topics comprises a general list of best practices for designing schema extensions effectively. Some of this we were fortunate enough to learn from others, but some of it comes from our own embarrassing mistakes.
Read All of Microsoft's Documentation Carefully
Unfortunately, we cannot cover all of the intricacies of schema development in this short book, so we recommend a thorough reading of the schema documentation at MSDN in addition to the nuggets of wisdom here. If possible, read the documentation twice (we did).
With that said, this topic is not that scary. Where there used to be some trepidation concerning changing Active Directory's schema (since it was "permanent"), today we can freely mess around with ADAM and even model our schema updates there first, to bring them to Active Directory later.
Register OIDs for New Classes and Attributes
All schema attributes must supply an Object Identifier (OID) to define the attribute or class uniquely across all LDAP directories. When we say "all LDAP directories," we really mean all of them, not just the ones internal to our organizations. Every OID used for a schema element should be unique globally. The OID is LDAP's version of the GUID (though the numbers have some meaning), and the LDAP specification requires it.
Warning: Do Not Invent OIDs!
This is a bad practice and can lead to trouble. When shipping a product that requires schema extensions, it is imperative to register the OID. Never use a tool like oidgen.exe to create a random OID for a schema extension you might actually deploy. This type of tool might be appropriate for throwaway ADAM instances, but it is inappropriate for any type of production schema extension, shipping or otherwise.
So, where can we get an OID? Probably the easiest method is through Microsoft: It turns out that the company offers a service to do this. An OID registered through this service is rooted in Microsoft's namespace, and in turn is used as the root for our custom OIDs. If the Microsoft OID service does not sound appealing, OIDs are also available from other standards bodies, such as the International Organization for Standardization (ISO), at no cost.
Developers planning on shipping a product that extends the Active Directory schema and wishing to get Windows logo certification must register their OID with Microsoft, regardless of where they obtained it originally.
Manage OID Namespaces Thoughtfully
If we had to register a brand-new OID for every single class and attribute we wanted to add to our directory, that process would be quite onerous. Luckily, we typically need to register only one or two OIDs for our entire organization and we are done. Here's how it works.
OIDs are essentially hierarchical naming structures, like the DNS system. Each additional OID suffix adds a new leaf to the tree. When we register to receive an OID from Microsoft, we will likely get a root-level OID similar to this:
At this point, we will want to create two branches under this OID for attributes and classes (see Table 7.1).
Subsequently, we can add attributes sequentially so that our first attribute might be named 1.2.840.113518.104.22.168.2.1, and so on. The whole schema process tends to be centralized, since we seldom want anyone to add to our domain's schema or to ADAM's schema willy-nilly. This turns out to be a good practice, since we want to avoid naming collisions where an OID is duplicated or a random OID is simply made up.
In summary, as long as we have obtained a root-level OID from a valid registrar, we are guaranteed that our OIDs will not collide with another organization's OIDs. After that, as long as our own organization can manage its OID namespace effectively, we won't step on our own toes either.
Practice on ADAM Instances
One thing about LDAP schemas that takes a little getting used to for SQL developers is that schema modifications are more or less permanent in Active Directory and ADAM. While it is possible to set schema objects to a defunct state that prevents them from being used, we cannot actually delete them. Furthermore, a variety of attributes on schema elements can be set only at creation time. We do not have the luxury of simply dropping our tables and starting over.
As such, schema extensions require a little bit more thought than what some developers might typically put into defining SQL schemas. Before ADAM, this process could be a little painful, as many organizations would keep around a "junk" Active Directory on which to test schema extensions. However, today we recommend modeling all of our schema modifications on ADAM first, when possible, since ADAM instances are easy to bring up and tear down. If we make a mistake (which we inevitably will), it is easy enough to simply start over. We don't often have the luxury of starting over with a production Active Directory schema mistake, so be sure to test thoroughly before moving to production.
Set the schemaIDGUID Attribute
There is an additional unique attribute that we can set on classes and attributes, called schemaIDGUID, which contains a GUID value. This GUID is typically used in Active Directory and ADAM for applying security settings to individual attributes in access control lists (ACLs). This is how the directory is able to apply such fine-grained access control on directory objects.
We really want to set this value explicitly, because Active Directory and ADAM will create a random GUID for us if we don't specify one. This creates problems when we install the same schema extensions in a development and production environment, because we will need to apply different access control entries in each environment, as each attribute will have a different GUID. However, if we set the GUID explicitly, then we can simply publish this information and make things easier for consumers of our schema. If you examine the MSDN Active Directory Schema reference documentation, you will notice that Microsoft follows this practice.
Use Company-Specific Prefixes on ldapDisplayNames
In practice, we are much more likely to receive a naming collision from the actual name of an attribute than from the OID or even the linkID values. For instance, if we were creating a directory-enabled product and we were providing our own schema extension for customers to install, choosing an attribute name like birthDate, ssn, or preferredName might be a bad idea. It is highly likely that someone in our customer base has already used these names in their own schema extensions. Instead, it is common practice to prefix our attributes with our company or organization name to try to keep them unique (e.g., acmeBirthDate or acme-BirthDate). This rule of thumb applies to both classes and attributes. We have even noticed that Microsoft has begun doing this for some of its newer schema extensions, using the msds- prefix.
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