Schema classes are defined as instances of the classSchema class. Table 4-4 shows the most important attributes that you may wish to set.
Table 4-4. The defining attributes of a classSchema object instance
Attribute |
Syntax |
Mandatory |
Multi-valued |
Description |
---|---|---|---|---|
cn |
Unicode |
Yes |
No |
The Relative Distinguished Name (RDN). |
governsID |
OID |
Yes |
No |
The OID that uniquely identifies objects of this class. |
lDAPDisplayName |
Unicode |
No |
No |
The name by which LDAP clients identify this class. |
schemaIDGUID |
Octet string |
Yes |
No |
Globally Unique Identifier (GUID) to uniquely identify this class. |
rDNAttID |
OID |
No |
No |
The attribute that indicates what two-letter-prefix (cn=, ou=, dc=) is used to reference the class. You should use only cn here unless you have a very solid idea of what you are doing and why. |
description |
Unicode string |
No |
No |
A description of the attribute. |
subClassOf |
OID |
Yes |
No |
The class that this one inherits from; the default is Top.[a] |
mustContain |
OID |
No |
Yes |
The list of attributes that are mandatory for this class. |
systemMustContain |
OID |
No |
Yes |
System version of the previous attribute. |
mayContain |
OID |
No |
Yes |
The list of attributes that are optional for this class. |
systemMayContain |
OID |
No |
Yes |
System version of the previous attribute. |
possSuperiors |
OID |
No |
Yes |
The list of Auxiliary (or 88-Class) classes that this object can be created within; e.g., User objects can be created within Organizational Unit objects. |
systemPossSuperiors |
OID |
No |
Yes |
System version of the previous attribute. |
auxiliaryClass |
OID |
No |
Yes |
The list of Auxiliary (or 88-Class) classes that this object inherits attributes from. |
systemAuxiliaryClass |
OID |
No |
Yes |
System version of the previous attribute. |
defaultSecurityDescriptor |
Octet string |
No |
No |
The Security Descriptor to assign to new instances of this class. Note that this SD is applied to new instances of the class if and only if an SD is not specifically provided and set during the creation of the instance. |
objectClassCategory |
Integer |
Yes |
No |
0 = 88-Class 1 = Structural 2 = Abstract 3 = Auxiliary |
systemOnly |
Boolean |
No |
No |
If True, once the initial value has been set, only the system can create and modify instances of this class. The default is False. |
objectClass |
Object |
Yes |
Yes |
The class that this object is an instance of; i.e., classSchema. |
nTSecurityDescriptor |
NT-Security- Descriptor |
Yes |
Yes |
Security Descriptor on the classSchema object itself. For example, setting an SD allows you to govern who can actually create instances of the object and who cannot. |
defaultHidingValue |
Boolean |
No |
No |
Whether the object is to be hidden or displayed within the MMCs by default. |
[a] Remember that the X.500 specifications indicate that an auxiliary class cannot inherit from a structural class, and an abstract class can inherit only from another abstract class. |
Classes are special in that they can inherit from one another. For example, let’s say that we wanted to store two new types of objects in the schema representing a marketing user and a finance user, respectively. These users both need all the attributes of the existing User class as a base. However, the finance user needs 7 special attributes, while the marketing user needs 3. The extra attributes required by both users do not match in any way. In this example, we can create a Marketing-User class, a Finance-User class, and 10 distinctly new attributes. However, rather than having to specify that the Marketing-User and Finance-User classes have each of the attributes of the original user class individually, all we need to do is specify that the new classes inherit from the user class by setting the subClassOf attribute to user. When we do this, both the new classes inherit every single attribute that the user class had. We can then add the extra attributes to each class and we have two new classes. It really is that simple.
You can think of the Active Directory schema as a treelike structure, with multiple classes branching down or inheriting from one base class at the top that has the attributes all objects need to begin with. This class, unsurprisingly enough, is called top, which was originally defined in the X.500 spec. Some classes inherit directly from top, while others exist much lower down the tree. While each class may have only one parent in this layout, each class may also inherit attributes from other classes. This is possible because there are three categories of classSchema object, known as the objectClassCategory, that you can create: structural, abstract, and auxiliary.
- Structural
If a class is structural, you can directly create objects of its type in Active Directory. The user and group classes are examples of structural classes.
- Abstract
It is possible that you would want to create a class that inherits from other classes and has certain attributes but that is not one you will ever need to create instances of directly. This type of class is known as abstract. For example, let’s say that the Marketing-User and Finance-User were to be the first of a number of structural classes that had a common structure. In that case, you could create an abstract class to be used as the basis of other structural classes. Abstract classes can inherit from other classes, can have attributes defined on them directly, and in all other ways act like structural classes, except that instances of them cannot directly be created as objects in Active Directory.
- Auxiliary
An auxiliary class is used to store sets of attributes that other classes can inherit. Auxiliary classes are a way for structural and abstract classes to inherit collections of attributes that do not have to be defined directly within the classes themselves. It is primarily a grouping mechanism.
The X.500 specifications indicate that an auxiliary class cannot inherit from a structural class, and an abstract class can inherit only from another abstract class.
Tip
To comply with the X.500 standards, there are actually four types of objectClassCategory. While objects are required to be classified as one of structural, abstract, or auxiliary by the 1993 X.500 specifications, objects defined before 1993 using the 1988 specifications are not required to comply with these categories. Such objects have no corresponding 1993 category and so are defined in the schema as having a special category known as the 88-Class.
Let’s take a look at the user and computer classes, which are used to create user and computer accounts, respectively, in Active Directory. The computer class (OID: 1.2.840.113556.1.3.30) and user class (OID: 1.2.840.113556.1.5.9) are each structural, which means that you can create objects with them directly in Active Directory. The computer class inherits from the user class, so the computer class is a special type of user in a way. The user class inherits from the organizationalPerson abstract class (OID: 2.5.6.7). This means that the total attributes available to objects of class computer include not only the attributes defined specifically on the computer and user classes themselves but also all the attributes that are inherited from the organizationalPerson class. The organizationalPerson class is a subclass of the person abstract class (OID: 2.5.6.6), which is a subclass of the abstract top class (OID: 2.5.6.0). There are no classes above top; it is the root class.
The user class that Microsoft needed to define in Active Directory had to be more than just the sum of the X.500 standard parts. After all, Microsoft uses Security Identifiers (SIDs) to identify users, and these were not contained in the original X.500 standards. So to extend the attributes that make up a user, Microsoft defined some auxiliary classes and included these in the user class makeup. The auxiliary classes are mailRecipient and securityPrincipal. mailRecipient is a collection of attributes that allow a user to hold information relating to the email address and mail account associated with that user. securityPrincipal is used to hold the SID and other user-related security attributes that Microsoft needed.
Figure 4-4 indicates how the computer class is made up from a number of other classes.
If you were to use a tool such as ADSI Edit, you could see the inheritance and class relationships quite clearly. For example, looking at the objectClass attribute of any user object, you would see that the values held in this attribute were top, person, organizationalPerson, and user. In other words, this attribute indicates that each user object inherits attributes from all these classes. Similarly, for any computer object, the objectClass attribute holds top, person, organizationalPerson, user, and computer. If you were to look at the subclassOf attribute on the computer class object itself in the schema, you would see the user class. The user class has a subClassOf attribute that indicates organizationalPerson, and so on.
Let’s now look at the user class in a little more depth. Using a tool like ADSI Edit, we can see the values of each attribute for the user classSchema object. Table 4-5 contains the attributes and values.
Table 4-5. Attributes and values for the user class
User attribute’s LDAP-Display-Name |
User attribute’s syntax |
Value contained in user’s attribute |
---|---|---|
adminDescription |
CASE_ IGNORE_ STRING |
User |
adminDisplayName |
CASE_ IGNORE_ STRING |
User |
cn |
CASE_ IGNORE_ STRING |
User |
defaultHidingValue |
BOOLEAN |
False |
distinguishedName |
DN_STRING |
|
instanceType |
INTEGER |
4 |
name |
CASE_ IGNORE_ STRING |
User |
nTSecurityDescriptor |
SECURITY_ DESCRIPTOR |
<SID> |
objectCategory |
DN_STRING |
|
objectClass |
CASE_ IGNORE_ STRING |
Top; classSchema (2 values of a multivalued attribute) |
objectGUID |
OCTET_ STRING |
<GUID> |
showInAdvancedViewOnly |
BOOLEAN |
True |
systemFlags |
INTEGER |
16 |
uSNChanged |
LARGE_INTEGER |
USN when last changed |
uSNCreated |
LARGE_INTEGER |
USN when created |
whenChanged |
UTC_TIME |
Time when last changed |
whenCreated |
UTC_TIME |
Time when created |
governsID |
CASE_ IGNORE_ STRING |
1.2.840.113556.1.5.9 |
defaultObjectCategory |
DN_STRING |
|
defaultSecurityDescriptor |
CASE_ IGNORE_ STRING |
Long text-encoded representation of a SID |
rDNAttID |
CASE_ IGNORE_ STRING |
cn |
lDAPDisplayName |
CASE_ IGNORE_ STRING |
User |
schemaIDGUID |
OCTET_ STRING |
<GUID> that uniquely identifies this class |
subClassOf |
CASE_ IGNORE_ STRING |
organizationalPerson |
systemAuxiliaryClass |
CASE_ IGNORE_ STRING |
securityPrincipal; mailRecipient |
systemMayContain |
CASE_ IGNORE_ STRING |
Various attributes[a] |
objectClassCategory |
INTEGER |
1 |
systemPossSuperiors |
CASE_ IGNORE_ STRING |
builtinDomain; organizationalUnit; domainDNS |
systemOnly |
BOOLEAN |
False |
[a] userCertificate; userWorkstations; userSharedFolderOther;userSharedFolder; userPrincipalName; userParameters; userAccountControl;unicodePwd; terminalServer; servicePrincipalName; scriptPath; pwdLastSet; profilePath; primaryGroupID; preferredOU; otherLoginWorkstations; operatorCount; ntPwdHistory; networkAddress; msRASSavedFramedRoute; msRASSavedFramedIPAddress; msRASSavedCallbackNumber; msRADIUSServiceType; msRADIUSFramedRoute; msRADIUSFramedIPAddress; msRADIUSCallbackNumber; msNPSavedCallingStationID; msNPCallingStationID; msNPAllowDialin; mSMQSignCertificatesMig; mSMQSignCertificates; mSMQDigestsMig; mSMQDigests; maxStorage; logonWorkstation; logonHours; logonCount; lockoutTime; localeID; lmPwdHistory; lastLogon; lastLogoff; homeDrive; homeDirectory; groupsToIgnore; groupPriority; groupMembershipSAM; gPOptions; gPLink; dynamicLDAPServer; desktopProfile; defaultClassStore; dBCSPwd; controlAccessRights; codePage; badPwdCount; badPasswordTime; adminCount; aCSPolicyName; accountExpires |
You can see the following about the user class:
The name of the class is user (adminDescription, adminDisplayName, cn, name).
It is an instance of the classSchema class (objectCategory and objectClass).
It inherits attributes from both top and classSchema (objectClass).
This object class has a SID governing who can access and manipulate it (nTSecurityDescriptor).
The instances of the user class are visible in normal browsing (defaultHidingValue).
The user class itself is to be hidden from casual browsing (showInAdvancedViewOnly).
The user class has an OID of 1.2.840.113556.1.5.9 (governsID).
It can have instances created by anyone (systemOnly).
It inherits attributes not only from top and classSchema but also from securityPrincipal and mailRecipient (objectClass and systemAuxiliaryClass).
When connecting to instances of the class via LDAP, the two-letter prefix used should be cn (rDNAttID).
The user class is a direct subclass of the organizationalPerson class (subClassOf).
There are a large number of attributes that instances of the user class can have values for (systemMayContain).
This class can be created directly under only three different parents in Active Directory (systemPossSuperiors).
The class is structural (objectClassCategory).
A default Security Descriptor should be applied to new instances of the user class if one is not specified on creation (defaultSecurityDescriptor).
Let’s look at the mustContain, mayContain, auxiliaryClass, possSuperiors, and their system attribute pairs. You can see that the only values that are set are systemPossSuperiors, systemMayContain, and systemAuxiliaryClass. These were the values set on the initial creation of the user class and cannot be changed. Note that there were no mandatory attributes set at the creation of the original class because the systemMustContain attribute is not listed. If you later wished to add an extra set of attributes or a new optional attribute to the user class, you could use auxiliaryClass or mayContain and modify the base definition. This occurs if, for example, you use the Active Directory Connector (ADC) to link your Active Directory and a Microsoft Exchange 5.5 schema. When you install the ADC for the first time in a forest, it extends the schema to include new Exchange objects and attributes, as well as modifying existing Active Directory objects to include new Exchange-relevant attributes. If you were to do this, the user class would be directly modified to include three of these Exchange-related auxiliary classes in the auxiliaryClass attribute: msExchMailStorage, msExchCustomAttributes, and msExchCertificateInformation. The ADC is discussed more fully in Chapter 16.
The attributes that are required when you create a new user are not listed in the mustContain attribute. That’s because objectSID, sAMAccountName, and the other attributes are inherited from other classes that make up this one. The mustContain attributes can be defined directly in auxiliaryClass, systemAuxiliaryClass, or subClassOf, or they can be defined on the classes inherited from further up the tree. Both sAMAccountName and objectSID, for example, are defined on the securityPrincipal class.
The same principle applies to the mayContain attribute. The entire set of these attributes is available only when you recurse back up the tree and identify all the inherited mayContain attributes on all inherited classes.
possSuperiors, on the other hand, can be made up of only those items defined directly on the class, those defined on the class in the subClassOf attribute, or any inherited classes defined on any other subClassOf attributes up the subClassOf tree. If that was too confusing, try this: an instance of the user class can have possSuperiors from itself, from the organizationalPerson class defined in the subClassOf attribute, from the person class (the organizationalPerson class’s subClassOf attribute), and from top (the person class’s subClassOf attribute).
Take a look at Figure 4-5. This shows the user class viewed with the Active Directory Schema snap-in. You can see the relevant general user data.
Notice that quite a bit of it is not configurable after the initial configuration, including governsID, schemaIDGUID, rDNAttID, objectClassCategory, systemOnly, objectClass, subClassOf, systemMustContain, systemPossSuperiors, systemMayContain, and systemAuxiliaryClass.
To see the so-called relationship settings (subClassOf, auxiliaryClass, systemAuxiliaryClass, possSuperiors, systemPossSuperiors), look at Figure 4-6. In this screen, you can see that the user class in this schema is inheriting attributes from the two auxiliary classes.
The third and final screen is the Attributes tab for the user class and is displayed in Figure 4-7. This shows the mustContain, systemMustContain, mayContain, and systemMayContain attributes of the user class.
With Windows 2000, auxiliary classes were statically linked to structural classes via the auxiliaryClass and systemAuxiliaryClass attributes. This went against how most directory services implemented auxiliary classes, which typically allowed dynamically assigned auxiliary classes on instances of objects. A new feature in Windows Server 2003 is the ability to do dynamic assignments of auxiliary classes to individual objects instead of to an entire class of objects in the schema. Having the dynamic auxiliary class mechanism provides much more flexibility for application developers who may want to utilize existing structural and auxiliary classes but do not want to extend the schema to define such relationships.
To dynamically link an auxiliary class to an object, you only need modify the objectClass attribute of the object to include the name of the auxiliary class. Any auxiliary class can be used, provided that all mustContain and systemMustContain attributes contained within the auxiliary class are set at the same time. You can also remove a dynamically linked auxiliary class by clearing any values that have been set for attributes defined by the auxiliary class and then removing the auxiliary class name from the object’s objectClass attribute.
Now let’s illustrate why dynamically linking auxiliary classes is a good idea. Assume we have a forest with several domains, each representing divisions within a company. Each division manages its own user objects. One of the divisions, named Toasters, wants to assign additional attributes to their user objects. These new attributes would only apply to employees within the Toasters division. Under Windows 2000, the only way to accomplish this would be to create the new attributes in the schema, create a new auxiliary class, and include the new attributes in the auxiliary class. At that point the new auxiliary class could be added to the auxiliaryClass of the user classSchema object. That means every user object contained within the forest would then have the new attributes. If each division wanted to do something similar, you can see how the number of attributes on all user objects within the forest could grow very quickly and unnecessarily. With Windows Server 2003, you would still create the new attributes and auxiliary classes in the schema, but you would not modify the auxiliaryClass of the user object. Instead, each division would dynamically link their auxiliary class to their user objects. This provides for a much more efficient and clean implementation than was possible under Windows 2000.
Get Active Directory, Second Edition now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.