O'Reilly logo

Active Directory, 3rd Edition by Alistair G. Lowe-Norris, Robbie Allen, Joe Richards

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Chapter 4. Active Directory Schema

The schema is the blueprint for data storage in Active Directory. Each object in Active Directory is an instance of a class in the schema. A user object, for example, exists as an instance of the user class. Attributes define the pieces of information that a class, and thus an instance of that class, can hold. Syntaxes define the type of data that can be placed into an attribute. As an example, if an attribute is defined with a syntax of Boolean, it can store True or False as its value.

Active Directory contains many attributes and classes in the default schema, some of which are based on standards and some of which Microsoft needed for its own use. However, the Active Directory schema was designed to be extensible, so that administrators could add any classes or attributes they deemed necessary. In fact, extending the schema is not a difficult task; it is often more difficult to design the changes that you would like to incorporate. Schema design issues are covered in Chapter 12, and in Chapter 27, we cover how to extend the schema programmatically. In this chapter, we're concerned only with the fundamentals of the schema.

Structure of the Schema

The Schema Container is located in Active Directory under the Configuration Container. For example, the distinguished name of the Schema Container in the mycorp.com forest would be cn=schema,cn=Configuration,dc=mycorp,dc=com. You can view the contents of the container directly by pointing an Active Directory viewer such as ADSIEdit or LDP at it. You can also use the Active Directory Schema MMC snap-in, which splits the classes and attributes in separate containers for easy viewing, even though in reality all the schema objects are stored directly in the Schema Container.

The schema itself is made up of two types of Active Directory objects: classes and attributes. In Active Directory, these are known respectively as classSchema (Class-Schema) and attributeSchema (Attribute-Schema) objects. The two distinct forms of the same names result from the fact that the cn (Common-Name) attribute of a class contains the hyphenated easy-to-read name of the class, and the lDAPDisplayName (LDAP-Display-Name) attribute of a class contains the concatenated string format that is used when querying Active Directory with LDAP or ADSI. In the schema, the lDAPDisplayName attribute of each object is normally made by capitalizing the first letter of each word of the Common-Name, and then removing the hyphens and concatenating all the words together. Finally, the first letter is made lowercase.[*] This creates simple names like user, as well as the more unusual sAMAccountName and lDAPDisplayName. We'll specify the more commonly used LDAP display name format from now on.

Whenever you need to create new types of objects in Active Directory, you must first create a classSchema object, defining the class of the object and the attributes it contains. Once the class is properly designed and added to the schema, you can then create objects in Active Directory that use the class. Alternatively, if you want to add a new attribute to an object, you must first create the attributeSchema object and associate the attribute with whatever classes you want to use it with.

Before we delve into what makes up an Active Directory class or attribute, we need to explain how each class that you create is unique not just within your Active Directory but also throughout the world.

X.500 and the OID Namespace

Active Directory is based on LDAP, which was originally based on the X.500 standard created by the ISO (International Organization for Standardization) and ITU (International Telecommunications Union) organizations in 1988. To properly understand how the Active Directory schema works, you really need to understand the basics of X.500; we'll run through them next.

The X.500 standard specifies that individual object classes in an organization can be uniquely defined using a special identifying process. The process has to be able to take into account the fact that classes can inherit from one another, as well as the potential need for any organization in the world to define and export a class of their own design.

To that end, the X.500 standard defined an Object Identifier (OID ) to uniquely identify every schema object. This OID is composed of two parts:

  • One to indicate the unique path to the branch holding the object in the X.500 treelike structure

  • Another to uniquely indicate the object in that branch

OID notation uses integers for each branch and object, as in the following example OID for an object:

    1.3.6.1.4.1.3385.12.497

This uniquely references object 497 in branch 1.3.6.1.4.1.3385.12. The 1.3.6.1.4.1.3385.12 branch is contained in a branch whose OID is 1.3.6.1.4.1.3385, and so on.

Tip

Each branch within an OID number also corresponds to a name. This means that the dotted notation 1.3.6.1.4.1, for example, is equivalent to iso.org.dod.internet.private.enterprise. As the names are of no relevance to us with Active Directory, we don't cover them in this book.

This notation continues today and is used in the Active Directory schema. If you wish to create a schema object, you need to obtain a unique OID branch for your organization. Using this as your root, you can then create further branches and leaf nodes within the root, as your organization requires.

The Internet Assigned Numbers Authority (IANA) maintains the main set of root branches. The IANA says of itself:

The central coordinator for the assignment of unique parameter values for Internet protocols. The IANA is chartered by the Internet Society (ISOC) and the Federal Network Council (FNC) to act as the clearinghouse to assign and coordinate the use of numerous Internet protocol parameters. The Internet protocol suite, as defined by the Internet Engineering Task Force (IETF) and its steering group (the IESG), contains numerous parameters, such as Internet addresses, domain names, autonomous system numbers (used in some routing protocols), protocol numbers, port numbers, management information base object identifiers, including private enterprise numbers, and many others. The common use of the Internet protocols by the Internet community requires that the particular values used in these parameter fields be assigned uniquely. It is the task of the IANA to make those unique assignments as requested and to maintain a registry of the currently assigned values. The IANA is located at and operated by the Information Sciences Institute (ISI) of the University of Southern California (USC).

You can find the IANA web page at http://www.iana.org.

You can request an OID namespace—i.e., a root OID number from which you can create your own branches—directly from the IANA if you like. These numbers are known as Enterprise Numbers. The entire list of Enterprise Numbers assigned by the IANA can be found at http://www.iana.org/assignments/enterprise-numbers/. This list of numbers is updated every time a new one is added. At the top of the file, you can see that the root that the IANA uses is 1.3.6.1.4.1. If you look down the list, you will see that Microsoft has been allocated branch 311 of that part of the tree, so Microsoft's OID namespace is 1.3.6.1.4.1.311. Leicester University's OID namespace is 1.3.6.1.4.1.3385. As each number also has a contact email address alongside it in the list, you can search through the file for any member of your organization that has already been allocated a number. It is likely that large organizations that already have an X.500 directory or that have developed SNMP MIBs will have obtained an OID.

Tip

In addition to Enterprise Numbers, country-specific OIDs can be purchased as well. An organization's Enterprise Number registration has no bearing on whether it has obtained a country-based OID namespace to use. If you don't see the company listed in the Enterprise Numbers list, don't be fooled; the organization could still have a number.

For example, Microsoft has been issued the Enterprise Number 1.3.6.1.4.1.311, yet all of its new schema classes use a U.S.-issued OID namespace of 1.2.840.113556 as their root. The 1.2.840 part is uniquely allotted to the United States. In other words, Microsoft has obtained two OID namespaces that it can use but is choosing to use only the U.S.-issued namespace.

If you want to obtain an Enterprise Number, fill in the online form at http://www.isi.edu/cgi-bin/iana/enterprise.pl. If this URL changes, you can navigate to it from the main IANA web page.

To assist customers in using properly assigned Enterprise Numbers, Microsoft has made a part of their namespace available for use. You can obtain an Enterprise Number from Microsoft's namespace by following the instructions at http://msdn.microsoft.com/certification/ad-registration.asp. At present, you send an email containing your company name, contact name, email address, phone number, schema prefix, and alternate prefix (in case your initial prefix is already taken) to . If you have an Enterprise Number from another source, you should still send an email to this address and register your Enterprise Number and prefix. This can help prevent collisions on prefix names with other companies, and also allows you to register for linkIDs used in linked attributes.

Tip

Companies who do not intend to produce schema updates for use outside of their own forests may not see a benefit in registering their prefix. The benefit for them comes into play if they find out someone else has already registered that name, or if some software vendor tried to register the name and they see it is already registered. For example, say you have the company MyCorp Financial Services that extends their schema with attributes with names such as mycorpAttrib1, mycorpAttrib2, etc. Then they purchase an application from MyCorp Software Solutions, who also chose to use attribute names of mycorpAttrib1, mycorpAttrib2, etc. MyCorp Financial Services would be in a very bad position. Their only option would be changing all previous uses of the attributes so it could be used by the application; otherwise, they can't use the application that they have purchased.

Once an organization has an OID namespace, it can add unique branches and leaves in any manner desired under the root. For example, Leicester University could decide to have no branches underneath and just give any new object an incrementing integer starting from 1 underneath the 1.3.6.1.4.1.3385 root. Alternatively, they could decide to make a series of numbered branches starting from 1, each corresponding to a certain set of classes or attributes that they wish to create. Thus, the fifth object under the third branch would have an OID of 1.3.6.1.4.1. 3385.3.5.

Warning

The range of values in any part of an OID namespace for the Active Directory schema goes from 1 to 268,435,455, i.e., from 20 through 228 - 1.

This limitation has caused issues with schema extensions for some companies in Australia. Australia has the OID 1.2.36, and according to the Australia Standards document MP-75, companies may use their Australian Company Number (excluding leading zeros) to formulate their OID without needing to request an OID. Unfortunately the ACN is nine digits, so it could easily exceed the limitation listed above. This has been filed as a bug and Microsoft is aware of the issue.

To reinforce this point, let's look at a couple of examples directly from the Active Directory schema. If you open the Active Directory Schema snap-in, you can look at the schema class OIDs very easily. Navigating through the classes when we open the property page for the printQueue class, we get Figure 4-1. You can see that the unique OID is 1.2.840.113556.1.5.23. This tells us that the number is a defined part of Microsoft's object class hierarchy.

printQueue Schema class properties

Figure 4-1. printQueue Schema class properties

Figure 4-2 shows the property page for the organizationalPerson class. Here, you can see that the unique OID 2.5.6.7 is very different, because within the original X.500 standard, a set of original classes was defined. One of these was organizationalPerson, and this is a copy of that class. Microsoft included the entire base X.500 classes within Active Directory.

Tip

The OID numbering notation has nothing to do with inheritance. Numbering a set of objects a certain way does nothing other than create a structure for you to reference the objects. It does not indicate how objects inherit from one another.

Let's dissect an example attribute and class to see what they contain. With that information, you will be able to see what is required when you create a new schema object.

organizationalPerson Schema class properties

Figure 4-2. organizationalPerson Schema class properties

Attributes (attributeSchema Objects)

Just as class information is stored in Active Directory as instances of the class called classSchema, attributes are represented by instances of the class called attributeSchema. As with all objects, the attributeSchema class has a number of attributes that can be set when specifying a new instance. The attributeSchema class inherits attributes from the class called top. However, most of the top attributes are not really relevant here. Table 4-1 shows the defining attributes of an instance of the attributeSchema class (i.e., an attribute) that can be set.

Table 4-1. The defining attributes of an attributeSchema object instance

Attribute

Syntax

Mandatory

Multivalued

Description

accessCategory

Integer

No

No

Used by the system.

attributeId

OID

Yes

No

The OID that uniquely identifies this attribute.

attributeSecurityGUID

GUID

No

No

GUID used to tie an attribute to a property set.

attributeSyntax

OID

Yes

No

Half of a pair of properties that define the syntax of an attribute. This one is an OID.

classDisplayName

Unicode string

No

No

The name displayed when viewing instances of the attribute.

cn

Unicode string

Yes

No

The Relative Distinguished Name (RDN).

defaultHidingValue

Boolean

No

No

Whether the object is to be hidden or displayed within tools by default.

description

Unicode string

No

No

A description of the attribute.

extendedCharsAllowed

Boolean

No

No

Whether extended characters are allowed in the value of this attribute.

isDefunct

Boolean

No

No

Whether the attribute is marked as disabled (i.e., unusable) in Active Directory.

isEphemeral

Boolean

No

No

Used by the system.

isMemberOfPartialAttributeSet

Boolean

No

No

Whether the attribute is held in the GC.

isSingleValued

Boolean

Yes

No

Whether this attribute is multivalued.

lDAPDisplayName

Unicode string

Yes

No

The name by which LDAP clients identify this attribute.

linkID

Integer

No

No

Whether the attribute is linked with another attribute (e.g., memberOf and member).

mAPIDisplayType

Integer

No

No

The integer by which MAPI clients identify this attribute.

objectClass

OID

Yes

Yes

This will hold the values attributeSchema and top to indicate that the value is an instance of those classes.

oIDType

Integer

No

No

Used by the system.

oMObjectClass

Octet string

No

No

Used by the system.

oMSyntax

Integer

Yes

No

Half of a pair of properties that define the syntax of an attribute. This one is an integer.

rangeLower

Integer

No

No

For strings, this is the minimum character length; for integers, it is the minimum value; otherwise, it is unused. It must be less than rangeUpper.

rangeUpper

Integer

No

No

For strings, this is the maximum character length; for integers, it is the maximum value; otherwise, it is unused.

schemaFlags

Integer

No

No

Used by the system.

schemaFlagsEx

Integer

No

No

Used by the system.

schemaIDGUID

Octet string

Yes

No

Globally Unique Identifier (GUID) to uniquely identify this attribute.

searchFlags

Integer

No

No

Integer with various bit flags that specify search and indexing information.

systemFlags

Integer

No

No

Integer with bit flags that define additional properties for the attribute.

systemOnly

Boolean

No

No

If true, once the initial value has been set, only the system can create instances of this attribute. Administrators cannot create instances of the attribute if this is set, but they can add this attribute to new or existing classes as required. The default is false.

The syntax of an attribute indicates the type of data that it holds, which we'll cover in a moment. The "Mandatory" column indicates whether the attribute must be set when initially creating an attributeSchema object. Attributes that are not mandatory do not have to be set when creating the object and can be defined later, if they are needed at all. The "Multivalued" column indicates whether the particular attribute can accept an array of values or whether it accepts only a single value; there are no multivalued attributes here other than objectClass.

Dissecting an Example Active Directory Attribute

The userPrincipalName (UPN ) attribute is used on user objects to provide a unique method of identifying each user across a forest. Users can log on to a workstation in any domain in the forest using the UPN if they so desire. The UPN attribute , in fact, accepts valid RFC 822 (email) addresses, so the UPN for user tpood in the emea.mycorp.com domain could be or , or even . In fact, any UPN suffix, such as , can be used in a forest. The only requirement is that the UPN value for a user is unique across all users in a forest.

Tip

Active Directory does not enforce uniqueness of a UPN when it is set. If two different users in the same forest are assigned the same UPN, neither will be able to log on using the UPN.

To dissect the attribute, we need to find out what values had been set for it. Perhaps the easiest way to do this is to use ADSIEdit from the Windows Support Tools, which can be installed from a Windows Server CD by running \Support\Tools\setup.exe. Table 4-2 shows the values of attributes that have been set for the userPrincipalName attribute.

Table 4-2. userPrincipalName's attributes

Attribute lDAPDisplayName

Attribute syntax

Attribute value

adminDescription

CASE_IGNORE_ STRING

User-Principal-Name

adminDisplayName

CASE_IGNORE_ STRING

User-Principal-Name

attributeID

CASE_IGNORE_ STRING

1.2.840.113556.1.4.656

attributeSecurityGUID

OCTET_STRING

GUID for Public Information property set

attributeSyntax

CASE_IGNORE_ STRING

2.5.5.12

cn

CASE_IGNORE_ STRING

User-Principal-Name

distinguishedName

DN_STRING

cn=User-Principal-Name, cn=Schema, cn=Configuration,dc=mycorp,dc=com

instanceType

INTEGER

4

isMemberOfPartialAttributeSet

BOOLEAN

True

isSingleValued

BOOLEAN

True

lDAPDisplayName

CASE_IGNORE_ STRING

userPrincipalName

name

CASE_IGNORE_ STRING

User-Principal-Name

nTSecurityDescriptor

SECURITY_ DESCRIPTOR

Binary representation of the Security Descriptor for the attribute.

objectCategory

DN_STRING

cn=Attribute-Schema, cn=Schema, cn=Configuration, dc=mycorp,dc=com

objectClass

CASE_IGNORE_ STRING

top; attributeSchema (two values of a multivalued attribute)

objectGUID

OCTET_STRING

<GUID>

oMSyntax

INTEGER

64

schemaIDGUID

OCTET_STRING

<GUID>

searchFlags

INTEGER

1 (Indexed)

showInAdvancedViewOnly

BOOLEAN

True

systemFlags

INTEGER

18 (Category 1 attribute, replicated to GC)

systemOnly

BOOLEAN

False

uSNChanged

LARGE_INTEGER

USN when last changed

uSNCreated

LARGE_INTEGER

USN when created

whenChanged

UTC_TIME

Time when last changed on this DC

whenCreated

UTC_TIME

Time when created

We can see that the name of the attribute is User-Principal-Name (adminDescription, adminDisplayName, cn, name), that it is an instance of the attributeSchema class (ob-jectCategory and objectClass), that it inherits attributes from both top and attri-buteSchema (objectClass), and that the UPN attribute is not visible to casual browsing (showInAdvancedViewOnly).

The userPrincipalName attributes show the following:

  • It is to be stored in the GC (isMemberOfPartialAttributeSet and systemFlags).

  • It is to be indexed (searchFlags).

  • It has an OID of 1.2.840.113556.1.4.656 (attributeID).

  • When binding to it with ADSI, we should use userPrincipalName (lDAPDisplayName).

  • Instances can be created by anyone (systemOnly).

  • It stores single (isSingleValued) Unicode strings (attributeSyntax and oMSyntax).

In Figure 4-3, you can see many of the values for the UPN attribute. We have indicated which attributes are changed by checking or unchecking each checkbox.

Attribute Properties

There are several properties on attributes that have significant and varied impact on attribute use and functionality. Here we give a little more detailed information on a few of these attributes that you need to understand when modifying the schema.

The UPN attribute as viewed by the Active Directory Schema snap-in

Figure 4-3. The UPN attribute as viewed by the Active Directory Schema snap-in

Attribute Syntax

The syntax of an attribute represents the kind of data it can hold; people with a programming background are probably more familiar with the term "data type." Unlike attributes and classes, the supported syntaxes are not represented as objects in Active Directory. Instead, Microsoft has coded these syntaxes internally into Active Directory itself. Consequently, any new attributes you create in the schema must use one of the predefined syntaxes.

Whenever you create a new attribute, you must specify its syntax. To uniquely identify the syntax among the total set of 21 syntaxes, you must specify 2 pieces of information: the OID of the syntax and a so-called OM syntax. This pair of values must be set together and correctly correlate with Table 4-3. More than one syntax has the same OID, which may seem strange; and to distinguish between different syntaxes uniquely, you thus need a second identifier. This is the result of Microsoft requiring some syntaxes that X.500 did not provide. Table 4-3 shows the 21 expanded syntaxes, including the name of the syntax with alternate names followed in parentheses.

Table 4-3. Syntax definitions

Syntax

OID

OM syntax

Description

Address

2.5.5.13

127

Used internally by the system

Boolean

2.5.5.8

1

True or false

Case-insensitive string

2.5.5.4

20

A string that does not differentiate between uppercase and lowercase

Case-sensitive string

2.5.5.3

27

A string that differentiates between uppercase and lowercase

Distinguished name

2.5.5.1

127

The Fully Qualified Domain Name (FQDN) of an object in Active Directory

DN-Binary

2.5.5.7

127

Octet string with binary value and DN. Format: B:<char count>:<binary value>:<object DN>

DN-String

2.5.5.14

127

Octet string with string value and DN. Format: S:<char count>:<string value>:<object DN>

Generalized-Time

2.5.5.11

24

ASN1.1 time format. e.g 20040625234417.0Z

Integer (enumeration)

2.5.5.9

10

A 32-bit number

Integer (integer)

2.5.5.9

2

A 32-bit number

Large integer

2.5.5.16

65

A 64-bit number

NT Security Descriptor

2.5.5.15

66

A Security Descriptor (SD)

Numeric string

2.5.5.6

18

A string of digits

Object ID

2.5.5.2

6

OID

Octet string (Octet-String)

2.5.5.10

4

A byte string

Print case string (IA5-String)

2.5.5.5

22

A normal printable string

Print case string (Printable-String)

2.5.5.5

19

A normal printable string

Replica-Link

2.5.5.10

127

Replication information

SID

2.5.5.17

4

A security identifier (SID)

Undefined

2.5.5.0

N/A

Not a valid syntax

Unicode

2.5.5.12

64

A wide string

UTC-Time

2.5.5.11

23

The number of seconds elapsed since 1 January 1970

Most of these are standard programming types. If you're not sure which syntax to use, take a look at a preexisting attribute and see if you can find an appropriate syntax for the attribute you wish to create. For example, the userPrincipalName attribute has an attributeSyntax of 2.5.5.12 and an oMSyntax of 64, so it must contain Unicode strings.

System Flags

The systemFlags attribute is an often overlooked but important attribute. The attribute is a series of bits representing how the attribute should be handled. The bits are cumulative so if bits 0 and 1 are set, the attribute will have the value of 3. New bit values can be defined any time that Microsoft updates the directory service binaries. This attribute is configured both on schema definitions of attributes and classes as well as on objects instantiated throughout the forest. This can be confusing but the various bits in the attribute can mean various things depending on the object the attribute applies to. Table 4-4 lists only the values for systemFlags on attributeSchema and classSchema objects.

Table 4-4. System flag values for class and attributes objects

Value

Description

1 (0x0001)

Attribute is not replicated.

2 (0x0002)

Attribute will be replicated to the global catalog. This value should only be set by Microsoft; do not use. Instead, use isMemberOfPartialAttributeSet attribute for adding attributes to PAS.

4 (0x0004)

Attribute is constructed , not stored in the database.

16 (0x0010)

Category 1 attribute or class. Category 1 objects are classes and attributes that are included in the base schema with the system. Note that not all classes and attributes included in the base schema are marked as category 1.

134217728 (0x08000000)

The schema object cannot be renamed.

Constructed attributes

Most attributes are directly stored in the Active Directory database. Constructed attributes are the exception and handled by the directory service to offer special functionality. This functionality can range from telling you approximately how many objects are contained directly under a container type object (msDS-Approx-Immed-Subordinates) to telling you the types of objects that can be instantiated under a given object (possibleInferiors) to telling you which attributes you have write access to on a given object (allowedAttributesEffective), and many other things. These attributes, because they are special, have some rules you should be aware of. These attributes:

  • Should not be replicated. They are constructed by each directory instance separately.

  • Cannot be used in server-side sorting.

  • Generally cannot be used for queries. The attribute aNR is an exception here as it is used for constructing the special ANR queries detailed in the section on search flags.

  • May require a BASE scope query to be retrieved for some constructed attributes ; e.g., tokenGroups can only be returned with a BASE scope query.

Category 1 objects

Category 1 objects are a subset of the attributes and classes that come with ADAM or Active Directory. They are marked with a special bit flag so that Microsoft can track and protect them from certain types of modifications.

Search Flags

The searchFlags attribute is generally known as the attribute used to control indexing , but it is a little more involved than that. As indicated by the name, searchFlags is similar to systemFlags in that it is a series of bits representing how the attribute should be handled. Unlike systemFlags, searchFlags are only set on schema attribute definitions. See Table 4-5 for all of the values as of Windows Server 2003 R2 and ADAM R2.

Table 4-5. Search flag bits

Value

Description

1 (0x0001)

Create an index for the attribute. All other index-based flags require this flag to be enabled as well. Marking linked attributes to be indexed has no effect.

2 (0x0002)

Create an index for the attribute in each container. This is only useful for one-level LDAP queries.

4 (0x0004)

Add attribute to Ambiguous Name Resolution (ANR) set. ANR queries are primarily used for Exchange and other address book tools. ANR attributes must be indexed and must be either UNICODE or Teletex string attribute syntax.

8 (0x0008)

Preserve this attribute in a tombstone object. This flag controls what attributes are kept when an object is deleted.

16 (0x0010)

Copy this value when the object is copied. This flag doesn't do anything in Active Directory; tools such as Active Directory Users and Computers that copy objects can look at this flag to determine what attributes should be copied.

32 (0x0020)

Create tuple index. Tuple indexing is useful for medial searches. A medial search has a wildcard at the beginning or in the middle of the search string. For example, the medial search (drink=*coke) would match Cherry Coke, Diet Coke, etc. This flag requires Windows Server 2003 or ADAM. V1.0.

64 (0x0040)

Create subtree index. This index is only available in ADAM R2 and is designed to increase performance of VLV queries. See the section "ADAM Schema" in Chapter 18.

128 (0x0080)

Mark attribute as confidential. Only users with both read property and Control Access right to the attribute so marked can view it when it is so marked. This is a new feature as of Windows Server 2003 SP1. SP1 domain controllers will not allow you to mark Category 1 attributes with this flag.

Indexed attributes

Attribute indexing is available to boost performance of queries. When an attribute is indexed, the values are placed in a special table in a sorted order so that a query using the attribute can be completed by looking at a subset of all the information in the directory. The type of index created can be modified by additional bit flags configured in the searchFlags attribute. There are several points to know about indexes:

  • A query that contains bitwise operations on an indexed attribute diminishes the usefulness of the index. A bitwise operation can't be directly looked up in the index table and the entire set of values in the index will have to be enumerated and tested.

  • A query that contains a NOT of an indexed attribute negates the use of the index for that portion of the query. A NOT of an attribute requires enumerating all objects in the search scope to determine which objects don't have the attribute or which objects have permissions applied that disallow the trustee to view the attribute value.

  • Linked attributes, due to internal implementation details, cannot be indexed. You can set the flag, but it will not create an index. This seems disheartening but all hope is not lost. Linked attributes are actually implicitly linked. Fortunately, Microsoft made this realization, and in Windows Server 2003 AD and ADAM, added the necessary logic to use these implicit indexes.

  • It is often assumed that indexes cannot be built or do not work well for attributes with multiple values or non-unique values. This is incorrect. In the early days of the original Active Directory beta, there was concern about multiple values and non-unique values but the issues surrounding them were cleared up. This topic is most often raised in regards to the objectClass attribute and is stated as the reason why the attribute wasn't indexed by default by Microsoft. Although Microsoft didn't index objectClass, it is an excellent candidate to be indexed and, in fact, early betas of the next server operating system have objectClass indexed.

ANR

Ambiguous Name Resolution is used for address book look-ups. It allows a single small query to be expanded into searching as many fields as the administrator would like searched so that users can enter a single piece of information and hopefully find all possible "hits" on the value they are interested in. When an ANR query such as:

    (anr=hansknecht)

is submitted, the Active Directory Query Processor expands the simple filter into a more complex OR wildcard filter that contains all attributes marked as part of the ANR set. The specified filter on a default ADAM installation would expand that simple query to:

(|
    (displayName=hansknecht*)
    (physicalDeliveryOfficeName=hansknecht*)
    (proxyAddresses=hansknecht*)
    (name=hansknecht*)
)

A Windows Server 2003 Active Directory domain with Exchange Server 2003 installed would expand the query to:

(|
    (displayName=hansknecht*)
    (mail=hansknecht*)
    (givenName=hansknecht*)
    (legacyExchangeDN=hansknecht)
    (msDS-AdditionalSamAccountName=hansknecht*)
    (mailNickname=hansknecht*)
    (physicalDeliveryOfficeName=hansknecht*)
    (proxyAddresses=hansknecht*)
    (name=hansknecht*)
    (sAMAccountName=hansknecht*)
    (sn=hansknecht*)
)

As you can see, a very simple query can quickly be expanded into a very large query. For this reason, you should avoid adding additional ANR attributes.

Preserve attribute in tombstone

When a delete request is processed for an object, the object is not immediately deleted. Instead, the object is stripped of most of its attributes and moved to the Deleted Objects container of the partition the object exists in, where it remains for the length of the tombstone period. This allows the delete operation to replicate to all domain controllers holding a copy of the object. The attributes that are retained when an object is tombstoned are configured through a combination of the searchFlags setting and some hard-coded internal functionality. The preserve on tombstone searchFlags setting is configurable by administrators so they can choose to add more attributes to what is kept on a tombstoned object. The purpose of keeping more attributes on tombstones is directly related to the new capability available in ADAM and Windows Server 2003 Active Directory to reanimate tombstoned objects. The more attributes you allow the directory to retain on the tombstoned object, the fewer attributes you have to recover through other means after the object is reanimated.

Unfortunately, not all attributes can successfully be added to the tombstone when the proper searchFlags bit is set. The most obvious examples are linked attributes. Linked attributes are handled differently, and there is no way to force them to be retained. If you configure a linked attribute to be preserved, AD will simply ignore the setting. This is unfortunate, as it means that critical information such as group membership must be either manually maintained in an additional attribute that can survive the tombstone process, or else the group membership must be maintained outside of AD.

While some attributes won't survive the tombstone regardless of what you set, some attributes will survive the tombstone but will not survive the reanimation process.

The attribute pwdLastSet attribute, for example, falls into this category. When you reanimate an object with pwdLastSet, even though the attribute may be preserved in the tombstone, it will be overwritten when the object is reanimated. Unfortunately, Microsoft has not documented what can and cannot survive a tombstone and subsequent reanimation. So make sure you test any attributes you have configured to be retained to make sure they can actually be reanimated. You don't want to first discover that information wasn't kept when you try to restore a critical object.

Tuple index

When you create an index, it is optimized for direct look-ups and, if the attribute syntax supports it, trailing wildcards—e.g., (name=joe*). If you use medial queries—that is, queries with wildcards anywhere but the end of the string such as (name=*oe)—performance tends to be rather less than optimal. Generally, this is OK, but in the cases where an important application is being significantly impacted due to poor medial query performance, you may want to consider enabling a tuple index for the attribute. This is just like enabling a normal index; you simply enable another bit to specify that a tuple index should be created.

A tuple index is considered an expensive index, and it will increase the DIT size more than a "normal" index. In addition, new attribute insertion performance will be impacted slightly. The performance hit will not be so much you would notice it on a single attribute insertion, but large bulk insertions could be impacted more significantly.

Confidential

A new bit for the searchFlags attribute was defined for Windows Server 2003 Service Pack 1: the confidential attribute flag. Any attribute that has this flag enabled requires two permissions in order to be viewed by a trustee. The trustee needs read property for the attribute and also needs control access for the attribute. This functionality was put into place primarily to protect sensitive user attributes such as social security numbers and other personal information. By default, only the administrators and account operators have full control on all user objects, which means they will be able to view any confidential attributes . Anyone else who has full control over a user object will also be able to view the confidential data, so this is yet another reason to not grant excessive rights in the directory. Obviously, if you have domain controllers in the domain (or GCs in the forest if you are dealing with a PAS-enabled attribute) that are not running Windows Server 2003 Service Pack 1, then any attributes marked as confidential will still be viewable on those DCs or GCs.

This capability was added as a workaround to issues that exist in the current security model in Active Directory. Unfortunately, there are a large number of explicit read property grant permissions on objects in Active Directory that are terribly difficult to easily override. This new flag allows you to step in despite all the default grant permissions and quickly deny access to an attribute.

This new function was welcomed with open arms in the Active Directory community until administrators started to realize that Microsoft purposely crippled the functionality by not allowing you to set Category 1 attributes as confidential. Category 1 attributes are many of the attributes defined in the default AD schema, and that list of attributes contains many of the attributes you probably want to make confidential such as telephone numbers, addresses, employee IDs, etc. It seems the intent is simply to give AD administrators a way to better secure additional attributes they add to the directory, which drastically reduces the usefulness of this capability for companies that stick to the default schema.

Tip

As mentioned, modification of searchFlags to enable confidential functions on Category 1 attributes is strictly disallowed by Windows Server 2003 SP1 domain controllers. If you try to change searchFlags on one of these DCs so that the confidential flag is set, you will get either an "Unwilling to perform" or a poorly worded "The search flags for the attribute are invalid. The ANR bit is valid only on attributes of Unicode or Teletex strings" error for your troubles.

If you are adamant about setting a Category 1 attribute as confidential, there is an option available. You can move the Schema FSMO to a non-SP1 domain controller and change searchFlags for the attribute on that domain controller. The validation is only performed on SP1 domain controllers, and once the value is set on any domain controller, it will replicate to the rest of the forest. Keep in mind that if you do this, you are directly going against the wishes of Microsoft for what should be set as confidential, which could have impact on the supportability of your environment. If you do choose to go forward, at the very least, avoid the attributes with systemFlags bit 1 (value 2) set. Those attributes are some of the most critical attributes in the directory, and it is quite unsafe to manipulate them.

This new capability is almost wholly underwhelming for ADAM. The default security descriptors on all ADAM base schema objects are configured with no explicit ACEs. The result is very few explicit read property grant permissions on objects when they are instantiated, which means you can more easily secure attributes with inherited deny permissions.

Next, we need to discuss the tools that Microsoft has made available with Service Pack 1 to handle granular delegation to trustees to view confidential attributes. The answer is easy: none. In order to grant a trustee the ability to view a specific confidential attribute on an attribute, a grant ACE with control access permission for the specific attribute needs to be added to the ACL of the object.[*]The GUI tools available for assigning permissions not only do not have the ability to assign this type of permission, they can't even display the permission if something else grants it. The command-line tool dsacls.exe is only marginally better; it can display the permission, but cannot grant the permission. The best that the GUI and dsacls.exe tool can do is assign either full control to the object or ALL control access rights to the object, but neither of these is optimal if you prefer to give minimum rights necessary to get the job done. In Windows Server 2003 SP1, the only way to set granular permissions to view a specific confidential attribute is to write a custom program or script to handle the delegation.

Tip

Windows Server 2003 R2 does supply a GUI tool to handle this delegation. The new version of LDP which is loaded in the %windir%\adam directory when you install R2 ADAM has a new ACL editor. This version of updated version of LDP is also available in the free download of ADAM SP1.

Property Sets and attributeSecurityGUID

Property sets are described in our Chapter 11 discussion on Active Directory security. We mention them here because the creation, modification, and identification of property sets involve the schema partition. Part of the information for a property set is maintained in the configuration container in the cn=extended-rights sub-container, and the rest is maintained in the schema.

The property sets are defined in the cn=extended-rights sub-container as controlAc-cessRight objects. Two of the attributes of the controlAccessRight object link it to the schema. The first attribute is the appliesTo attribute; the second is the rightsGuid. The appliesTo attribute is the string representation of the schemaIDGUID attribute of the classSchema objects that the property set applies to. The rightsGuid is the string representation of the binary GUID stamped on the attributeSecurityGUID attribute of attributeSchema objects to identify them as members of the property set.

Linked Attributes

Microsoft allows distinguished name attributes with attributeSyntax values of 2.5.5.1, 2.5.5.7, and 2.5.5.14 to be linked to attributes with an attributeSyntax of 2.5.5.1. These are called linked attributes and consist of a forward link and a back link. An example of a pair of linked attributes is member and memberOf.

Attributes are linked by setting the linkID attributes of two attributeSchema objects to valid link values. The values must be unique for all attributeSchema objects. The value of the forward link is a positive even value and the back link is the forward linkID value plus one to make it a positive odd value. Attributes must be linked when they are first defined in the schema.

You can use any random linkID values as long as they result in a unique linkID pair however, it is highly recommended that you either auto-generate linkIDs or request linkIDs from Microsoft for your use. Requesting linkIDs from Microsoft is quite easy once you have registered a schema prefix and Enterprise ID with Microsoft. Simply go to the web page http://msdn.microsoft.com/certification/ADLinkID.asp and follow the instructions.

If you don't want to request linkIDs from Microsoft and you are using Windows Server 2003 AD or ADAM, you have the alternate safe option of letting the directory service create a linkID pair for you. Microsoft has not, to this point, officially documented this new capability. However, a Microsoft employee named Eric Fleischman has documented the capability on his blog at http://blogs.technet.com/efleis/archive/2004/10/12/241219.aspx. The process is quite simple; however, the linkID pairs created are specific to the directory in which they are created. Do not copy the linkID pair values to other Active Directory or ADAM instances; auto-generate new links in the new instances instead.

To auto-generate linkID pair values, you first create the forward link attribute with any standard mechanism for extending the schema; for the linkID attribute, you must specify the OID value 1.2.840.113556.1.2.50. After the forward link attribute is created, you must refresh the schema cache. The next step is the creation of the back link attribute, for the linkID attribute, you must specify the lDAPDisplayName of the forward link. Finally, you must refresh the schema cache again. As you can see, the process is indeed quite simple and painless.

Classes (classSchema Objects)

Schema classes are defined as instances of the classSchema class. Table 4-6 shows the most important attributes that you may wish to set.

Table 4-6. The defining attributes of a classSchema object instance

Attribute

Syntax

Mandatory

Multivalued

Description

auxiliaryClass

OID

No

Yes

The list of Auxiliary (or 88-Class) classes that this object inherits attributes from.

Cn

Unicode

Yes

No

The Relative Distinguished Name (RDN).

defaultHidingValue

Boolean

No

No

Whether the object should be hidden or displayed within the MMCs by default.

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.

Description

Unicode string

No

No

A description of the attribute.

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.

mayContain

OID

No

Yes

The list of attributes that are optional for this class.

mustContain

OID

No

Yes

The list of attributes that are mandatory for this class.

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.

objectClass

Object

Yes

Yes

The class that this object is an instance of; i.e., classSchema.

objectClassCategory

Integer

Yes

No

0 = 88-Class

1 = Structural

2 = Abstract

3 = Auxiliary

possSuperiors

OID

No

Yes

The list of classes that this object can be created within; e.g., user objects can be created within Organizational Unit objects.

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.

schemaIDGUID

Octet string

Yes

No

Globally Unique Identifier (GUID) to uniquely identify this class.

subClassOf

OID

Yes

No

The class that this one inherits from; the default is top.

systemAuxiliaryClass

OID

No

Yes

System version of auxiliaryClass.

systemFlags

Integer

No

No

Integer with bit flags that define additional properties for the class.

systemMayContain

OID

No

Yes

System version of mayContain.

systemMustContain

OID

No

Yes

System version of mustContain.

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.

systemPossSuperiors

OID

No

Yes

System version of possSuperiors.

Object Class Category and Inheritance

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 seven special attributes, while the marketing user needs three. 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 of 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.

Tip

You have another option when using Windows Server 2003 Forest Functional Mode or ADAM to resolve this issue. First, define the additional attributes and then create two auxiliary classes and assign the attributes to the classes. Then you can dynamically assign the auxiliary classes to users on ad-hoc basis. This is far more flexible in that you can easily reconfigure individual users as necessary. If a user moves from Marketing to Finance, using special inherited classes would require deleting the user and recreating the user with the finance-user class. With dynamic auxiliary classes, you would simply clear the marketing attributes, remove the Marketing auxiliary class, and add the Finance auxiliary class and attributes.

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 you can create three categories of classSchema object, also known as the objectClassCategory : 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 be directly 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, within 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 instantiate objects of those classes 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. The securityPrincipal attribute 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 ADSIEdit, 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.

The computer class

Figure 4-4. The computer class

Dissecting an Example Active Directory Class

Let's now look at the user class in a little more depth. Using a tool like ADSIEdit , we can see the values of each attribute for the user classSchema object. Table 4-7 contains the attributes and values.

Table 4-7. 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

defaultObjectCategory

DN_STRING

cn=person, cn=schema, cn=configuration, dc=mycorp, dc=com

defaultSecurityDescriptor

CASE_ IGNORE_ STRING

SDDL text-encoded representation of the default security descriptor

distinguishedName

DN_STRING

cn=User, cn=Schema, cn=Configuration, dc=mycorp, dc=com

governsID

CASE_ IGNORE_ STRING

1.2.840.113556.1.5.9

instanceType

INTEGER

4

lDAPDisplayName

CASE_ IGNORE_ STRING

user

name

CASE_ IGNORE_ STRING

User

nTSecurityDescriptor

SECURITY_ DESCRIPTOR

Binary representation of the Security Descriptor for the class

objectCategory

DN_STRING

cn=Class-Schema, cn=Schema, cn=Configuration, dc=mycorp, dc=com

objectClass

CASE_ IGNORE_ STRING

top; classSchema (two values of a multivalued attribute)

objectClassCategory

INTEGER

1

objectGUID

OCTET_ STRING

<GUID>

rDNAttID

CASE_ IGNORE_ STRING

cn

schemaIDGUID

OCTET_ STRING

<GUID> that uniquely identifies this class

showInAdvancedViewOnly

BOOLEAN

True

subClassOf

CASE_ IGNORE_ STRING

organizationalPerson

systemAuxiliaryClass

CASE_ IGNORE_ STRING

securityPrincipal mailRecipient

systemFlags

INTEGER

16 (Category 1 class)

systemMayContain

CASE_ IGNORE_ STRING

Various attributes. See discussion.

systemOnly

BOOLEAN

False

systemPossSuperiors

CASE_ IGNORE_ STRING

builtinDomain organizationalUnit domainDNS

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

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 security descriptor 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 not 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 security-Principal 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).

  • 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).

  • There are a large number of attributes that instances of the user class can have values for (systemMayContain). Values include:

accountExpires
msDS-User-Account-Control-Computed
aCSPolicyName
msIIS-FTPDir
adminCount
msIIS-FTPRoot
badPasswordTime
mSMQDigests
badPwdCount
mSMQDigestsMig
businessCategory
mSMQSignCertificates
codePage
mSMQSignCertificatesMig
controlAccessRights
msNPAllowDialin
dBCSPwd
msNPCallingStationID
defaultClassStore
msNPSavedCallingStationID
desktopProfile
msRADIUSCallbackNumber
dynamicLDAPServer
msRADIUSFramedIPAddress
groupMembershipSAM
msRADIUSFramedRoute
groupPriority
msRADIUSServiceType
groupsToIgnore
msRASSavedCallbackNumber
homeDirectory
msRASSavedFramedIPAddress
homeDrive
msRASSavedFramedRoute
homePhone
networkAddress
initials
ntPwdHistory
lastLogoff
o
lastLogon
operatorCount
lastLogonTimestamp
otherLoginWorkstations
lmPwdHistory
pager
localeID
preferredOU
lockoutTime
primaryGroupID
logonCount
profilePath
logonHours
pwdLastSet
logonWorkstation
scriptPath
mail
servicePrincipalName
manager
terminalServer
maxStorage
unicodePwd
mobile
userAccountControl
mS-DS-CreatorSID
userCertificate
msCOM-UserPartitionSetLink
userParameters
msDRM-IdentityCertificate
userPrincipalName
msDS-Cached-Membership
userSharedFolder
msDS-Cached-Membership-Time-Stamp
userSharedFolderOther
msDS-Site-Affinity
userWorkstations

How inheritance affects mustContain, mayContain, possSuperiors, and auxiliaryClass

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 17.

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.

Warning

Do not mistake attributes that a class must contain with the attributes that you must explicitly set on object instantiation. Unfortunately there is no effective way to programmatically determine what attributes you need to set on an object when you create an instance of the class. Some of the attributes that an object must contain are system-owned and can only be set by the system, other attributes are optional and will be populated automatically, and finally some attributes are actually required to be specified by the objects creator. To confuse the situation even more, various versions of the OS or ADAM change the requirements.

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.

The possSuperiors attribute, 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).

Viewing the user class with the Active Directory Schema snap-in

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.

User class schema entry general settings

Figure 4-5. User class schema entry general settings

Notice that quite a bit of it is not configurable after the initial configuration, including:

governsID
subClassOf
schemaIDGUID
systemMustContain
rDNAttID
systemPossSuperiors
objectClassCategory
systemMayContain
systemOnly
systemAuxiliaryClass
objectClass
subClassOf

To see the so-called relationship settings (subClassOf, auxiliaryClass, systemAuxili-aryClass, 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.

User class schema entry relationship settings

Figure 4-6. User class schema entry relationship settings

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 system-MayContain attributes of the user class.

Dynamically Linked Auxiliary Classes

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 dynamically assign 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.

User class schema entry attribute settings

Figure 4-7. User class schema entry attribute settings

Warning

Dynamic linking of auxiliary classes requires Windows Server 2003 Forest Functional Mode.

To dynamically link an auxiliary class to an object, you only need to 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 cleaner and much more efficient implementation than was possible under Windows 2000.

Warning

When you dynamically link an auxiliary class to an object, the auxiliary class is listed in the objectClass listing for the object. When an auxiliary class is statically linked, the auxiliary class is not listed in the objectClass listing. This can cause issues with applications that determine available attributes on an object and only look at the schema definitions of an object class or at the objectClass attribute of the object itself.

Summary

In this chapter, we've shown you how the internal blueprint for all objects in Active Directory, known as the schema, was derived from the X.500 directory service. We explained the purpose of the OID numbering system and how it can be used. We then detailed how an attribute and its syntax are structured in the schema as attributeSchema objects, using the userPrincipalName attribute as an example. We showed how attributes are added to classes by detailing how classes are stored in the schema as instances of classSchema objects. To make this more clear, we dug into the details of the user class to see how it was constructed. Finally, we covered how auxiliary classes can be dynamically linked in Windows Server 2003 and why it is significant.

Chapter 12 builds on what you've learned here to demonstrate how you can design and implement schema extensions.



[*] Names defined by the X.500 standard don't tend to follow this method. For example, the Common-Name attribute has an LDAP-Display-Name of cn, and the Surname attribute has an LDAP-Display-Name of sn.

[*] Confused? Check out the security chapters, and this will become clear.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required