Active Directory Schema
When discussing directory service structure and operation up to this point, I've used general terms that are applicable to just about any LDAP implementation. It's now time to spend a while looking at specific features in Active Directory. You may find this information to be a little too much detail for helping you manage day-to-day operations in Windows Server 2003. However, it's good to know some of the important functional and operational details of the directory service to help you create reliable domain designs and to troubleshoot problems that arise.
As a quick review, the object-oriented LDAP database that comprises Active Directory is structured around a set of object classes and their associated attributes. Individual objects are instances of specific object classes. The schema defines the available object classes, their associated attributes, the data types and permitted ranges for those attributes, and the rules for arranging and managing objects within the Active Directory database.
Schema Functional Operation
To visualize how the schema works, consider a simple, paper-based directory. Every month or so I get a catalog from Land's End, the clothing retailer. This catalog is a database of sorts, similar to a directory service except that it guides the user to a garment instead of a network entity. Consider this:
The schema for this directory defines a set of object classes with the scope "Garments Sold by Land's End." These classes represent objects of interest to garment purchasers, such as Sweaters, Suits, Blazers, Accessories, and so forth.
The schema also defines the available attributes that can be associated with the object classes, such as Size, Color, Inseam-Length, and Price, along with more subtle attributes specific to the directory itself, such as Picture-Of-Garment.
The schema has content rules that define what attributes can be associated with a class. Some attributes, like Size and Color, might be associated with nearly every class. An attribute like Inseam-Length, however, might only be associated with classes like Slacks and Jeans, not Sport-Coats or Shoes.
Some garment classes have attributes that are nearly identical. For example, the attributes that define the Polo-Shirts class differ only slightly from the attributes that define the Sport-Shirts class. The Polo-Shirts class derives from the Sport-Shirts class and inherits the attributes associated with its parent. The new attributes are then just tacked on to the new class.
Class inheritance makes it important to have structure rules that keep the directory aligned with the real world. For example, a structure rule prevents placing an object from the Bathrobe class under a container from the Shoe class.
A particular garment is an instance of its garment class. For example, an instance of the Blazer class would be the solid red blazer with green plaid lining that I gave my brother for Christmas last year. (The snide thank you note I received in return came from the Hallmark directory service as an instance of the Ungrateful-Sibling class.)
The Land's End schema has syntax rules that define the values that can be associated with an attribute. For example, the Size attribute must have whole integer values while the Shoe-Size attribute can have real number (fractional) values.
Because the garment classes and their attributes can change, the Land's End directory is extensible. For example, a new attribute called Number-Of-Sleeve-Buttons can be added and the Blazers class modified to include that attribute.
For flexibility, certain special object classes can be dynamically assigned to a specific object. This makes it possible to create special bundles of attributes for a certain object like a Rad-Phat T-shirt object without altering all other instances of the T-shirt class.
I know this was a long example, so here are the key terms and concepts:
Define the objects that can appear in Active Directory and their associated attributes.
Define a method for building new object classes out of existing object classes.
Define the available attributes. This includes extended attributes that govern actions that can be taken on object classes.
Determine possible tree arrangements.
Determine the type of value an attribute is capable of storing.
Determine the attributes that can be associated with a given class.
Additions can be made to the list of available classes and attributes.
Dynamic class assignments.
Certain classes can be dynamically assigned to a specific object rather than an entire class of objects.
Object Classes and Class Derivations
An object class is nothing more than a bundle of attributes with a name. The User class, for example, has certain attributes that, taken together, make it distinct from the Organizational-Unit class or the Server class. The X.500/9594 standard as modified by RFC 2256, "A Summary of the X.500(96) User Schema for use with LDAPv3," defines 21 classes and 55 attributes in a standard LDAP directory schema.
The Active Directory schema extends this list quite a bit, out to nearly 200 classes and just under 1700 attributes. If you want a complete list, check out the Windows Server 2003 Platform SDK or look at the MSDN web site, msdn.microsoft.com.
The Active Directory schema includes all RFC 2256 classes, except for Alias and Strong-Authentication-User, and all attributes, except for Aliased-Object-Name. The exclusion of Alias was deliberate. Aliases are a notorious source of performance difficulties and integrity problems in directory services. In addition, most of the object classes that would normally be given aliases are required to have unique names in Active Directory. This includes Users, Computers, and Groups.
Windows .NET includes the inetOrgPerson class as defined in RFC 2798, "Definition of the inetOrgPerson Object Class." This makes Active Directory more compatible with Netscape Directory Services and Novell Directory Services, both of which derive their User class from inetOrgPerson.
It's not enough to define schema components in terms of objects, actions, and relationships. Laws and customs are also necessary to avoid anarchy. These take the form of schema rules. Directory service designers build certain rules into the schema that determine how classes and attributes are used, what kind of values they can have, and what relationship they have to each other. These rules fall into three categories:
Frank Lloyd Wright established the design paradigm for twentieth century architecture by declaring that form should always follow function. He was a building architect rather than directory services architect, of course, but Active Directory is as much of a monument to form and function as a prairie house, and it is the structure rules that accomplish this.
There is really only one structure rule in Active Directory: Each object class has only certain classes that can be directly above it, called Possible Superiors. This structure rule is very important because classes inherit attributes from their parents. Structure rules prevent putting a User class object under a totally unrelated container class, like IPSEC-Base or NTDS Settings.
Every object class has certain attributes with values that cannot be left blank when an object is instantiated. These are called must-contain attributes. For example, every instance of the User class must have a value for the Common-Name attribute. Other attributes are optional and are designated may-contain attributes.
An important design principle of Active Directory is that only attributes with values are stored in the database. This greatly reduces the size and complexity of the database. Because attributes can be added after an object is created and then later removed if they are set to null, the database engine must constantly pack and repack the data. This is done by a garbage collection service that runs every 12 hours.
Attributes store data. Data must have a data type to define the storage requirements. Real numbers have a different form from integers, which are different from long integers, which are different from character strings.
An attribute can have only one data type. It cannot hold a string when associated with one object class and an integer when associated with another. The syntax rules in the schema define the permissible values types and ranges for the attributes.
Schema Definition Objects
Individual objects are always instances of an object class. Achieving this design principle involves using a template that defines the attributes, schema rules, and class hierarchy for the objects within an object class. The same applies for attributes, which require a template to define the syntax rules. This suite of templates makes up the schema definitions for a directory service information store.
Some directory services put the schema definitions into a separate file that is loaded at boot time or whenever the schema requires changing. In contrast, the Active Directory schema is self-referential. That is to say, all class definitions, attribute definitions, and schema rules are part of the schema itself. An appropriate title for an Active Directory schema self-help book would be Everything I Need to Know I Learned from Myself.
The Active Directory schema contains two schema object classes, ClassSchema and AttributeSchema. Objects derived from these classes act like patterns in a lathe to turn out other objects. The schema objects are stored in the directory in the cn=Schema,cn=Configuration,dc=<domain_name>,dc=<domain_root> container.
In addition to ClassSchema and ClassAttribute classes, the Schema container holds a class called SubSchema with one instance, an object called Aggregate. The distinguished name of this object is cn=aggregate,cn=schema,cn=configuration,dc=company,dc=com. The purpose of Aggregate is to provide a single point for LDAP clients to discover information about the Active Directory schema. Without this object, clients would be forced to perform expensive scans of the entire Schema container.
We've completed the overview of the schema structure, function, and rules. Before moving forward, let's look at how Active Directory uniquely identifies objects. This information is crucial to understanding the more advanced Active Directory tools. Here is a brief attribute listing for a sample User object made using the LDIFDE utility. The unique identifiers are highlighted:
C:\>ldifde -d cn=bgates,cn=users,dc=dotnet,dc=com -f con
Connecting to "DC01.Company.com"
Logging in as current user using SSPI
Exporting directory to file con
Searching for entries...
Writing out entries.dn: CN=bgates,CN=Users,DC=dotnet,DC=com
Because LDAP uses an object-oriented database, it is important that each object has a unique path in the namespace, similar to the way that a filename and path must be unique in a file system.
The Distinguished Name (DN) attribute of an object defines the LDAP path all the way to the root of the namespace; therefore, the DN must be unique. If you move an object to a different container in Active Directory, in reality, you are simply changing the DN.
Globally Unique Identifier (GUID)
In classic Exchange, Microsoft used the DN as the unique database row identifier for objects in the directory service store. This unfortunate engineering decision created a configuration problem for Exchange. When an object is moved, its DN changes, but a unique row identifier in a database cannot ever change. For this reason, in Exchange 5.5 and earlier, mailbox recipients cannot be moved but must be freshly created and then linked to a User account in the SAM.
To avoid that problem in Active Directory, Microsoft used a different unique row identifier called the Globally Unique Identifier, or GUID . A GUID is created using an algorithm that virtually guarantees its uniqueness within a system.
Using a GUID permits you to move objects at will between containers in Active Directory without changing the unique row numbers for the objects, thereby maintaining internal referential integrity in the database. Keep this behavior in mind, because you'll see it at work when we discuss the role of the Infrastructure Master in keeping track of group members from other domains.
Microsoft uses the GUID algorithm in a variety of different circumstances. You will see them in designators used to identify COM objects and OLE registrations. Group policies use the GUID algorithm to create a unique folder name for each policy. The operating system identifies hardware using GUIDs during Plug-and-Play enumeration. GUIDs also go by the names Universally Unique Identifier (UUID) and Class ID (CLSID).
Security Identifier (SID)
Three classes of Active Director objects can be placed on the access control lists (ACLs) used to protect security objects. These object classes are User, Computer, and Group. Together, they are termed security principals.
A security principal is assigned a unique number called a Security Identifier, or SID. This is exactly the same SID used by NT to identify users, groups, and computers. A SID for a security principal is made up of the SID of the security principal's domain and a unique suffix, called a Relative ID, or RID. The series of RIDs for security principals that can be created by an administrator start at decimal 1000. For example, the first User account created following the creation of a domain would be given RID 1000. The next object, call it a group, would be RID 1001, and so forth.
The combination of a domain SID and a RID form a unique number within a domain and within a forest. The pool of RIDs is maintained by a specially designated Windows Server 2003 domain controller called a RID Master.
SAM Account Name
In an NT domain, every object in the SAM must have a unique name. This is true for computers, users, and groups. A unique name guarantees that the object will have a unique NetBIOS presence in the network as well as a one-to-one correspondence between the logon name (in the case of users and computers) and the SID used to control resource access.
The same restriction is left in place in Windows 2000 and Windows Server 2003. Every user, computer, and group in a domain must have a unique name. This attribute is called SAMAccountName, although you might hear it called logon name or flat name. When you create a new security principal, regardless of the container where you place the object, it must have a unique flat name in the domain.
User Principal Name (UPN) and Service Principal Name (SPN)
Just as unique flat names identify security principals in NetBIOS, User Principal Names (UPNs) identify security principals within the hierarchical LDAP namespace in Active Directory. A UPN takes the form User@Company.com.
Unique UPNs ensure that users can log on with their UPN rather than the classic domain\username construct. The Global Catalog is used to "crack" the UPN into its constituent parts.
To assure uniqueness, when a security principal is created, the system refers to the Global Catalog to verify that the UPN has not already been used. If a GC server is not available, the system displays an error message prompting the administrator to wait until a GC is available so that uniqueness can be verified.
In a Parent/Child trust configuration, the UPN suffix of the root domain is assigned to every security principal. In a Tree Root trust configuration, you must manually assign a common UPN suffix. This is done using the Properties window of the domain tree in the AD Domains and Trusts console.
Object Identifier (OID)
In addition to the attributes that assure uniqueness of a particular object, Active Directory needs a way to assure that objects of the same class all come from the same Schema object. This is done by assigning a unique Object Identifier, or Object Identifier (OID) to each object in the Schema naming context. ISO defines the structure and distribution of OIDs in ISO/IEC 8824:1990, "Information Technology—Open Systems Interconnection—Specification of Abstract Syntax Notation One (ASN.1)."
ASN.1 provides a mechanism for standards bodies in various countries to enumerate standard data items so that they do not conflict with one other. ASN.1 governs more than just directory services classes and attributes. For example, OIDs are used extensively in SNMP to build hierarchies of Management Information Base (MIB) numbers. They are also assigned to many items associated with the Internet. If you're interested in the list of organizations that assign OID numbers and their hierarchy, it is available at ftp.isi.edu/in-notes/iana/assignments/enterprise-numbers.
If you ever need to create a new attribute or object class in Active Directory, you must have a unique OID. There are a couple of ways to get one. The first is to apply to ANSI for your own numerical series. This costs a few thousand dollars and takes a while to process. The other is to use the OIDGEN utility from the Resource Kit. This will generate a Class and an Attribute OID out of Microsoft's address space. The disadvantage to using OIDGEN is that the resultant number is very, very, very long. Here is an example:
Attribute Base OID:
Class Base OID:
Many thanks to Harald Alvestrand, who made good use of a long winter in Trondheim, Norway, to build a hyperlinked tree showing many of the common OID registrations. His information is now slightly out of date but the structure is still valid and very instructive. Visit his web site at www.alvestrand.no/objectid.