joeware - never stop exploring... :)

Information about joeware mixed with wild and crazy opinions...

Searching for users with the LDAP Filter (objectClass=user)…

by @ 10:18 pm on 3/24/2007. Filed under tech

…is generally a very bad idea. Why, because in Windows 2000 and Windows Server 2003 AD, objectClass is not, by default, indexed.

What does that mean you ask? It means that your query is going to be way slow because it has to look at every single object in the search scope of the query with the attribute objectClass populated (basically ALL of the objects) will have to be looked at to determine if it is a match or not. Say you have 10,000 objects in your domain and you have 20 users. You will have to look at 10,000 objects to find those 20 users.

The better query is to use (&(objectCategory=person)(objectClass=user)) or possibly (samAccountType=805306368). These queries take advantage of indexed attributes which means things will go much better for you and you will have to look at far fewer objects for matches, hopefully JUST the objects that do match.  

See also http://blog.joeware.net/2005/12/08/147/

There is an easy way to correct this issue if you want to continue to use (objectClass=user), index the attribute.

WHOA!!! Hold on!“, you say. “You don’t just want to index that attribute, it will break something. Someone from MSFT told me that Active Directory can’t properly Index multi-value non-unique attributes and that is specifically why objectClass isn’t indexed by default…“. Yes I heard that same rumor as well, multiple times in fact. When I dug into it, I found that the rumor did indeed seem true…. but only back in the early Windows 2000 beta’s. The bright folks on the DS team realized that that kind of crap wouldn’t fly in the real world and so corrected the issue. Unfortunately no one got around to correcting the over sight with objectClass by the time RTM came around so objectClass went out without an index and directories everywhere suffer for it when applications only use objectClass with other non-indexed attributes for their queries. Exchange was a perfect example of this for a long time.

I recommend you do some level of analysis on your directory with say Server Performance Advisor and check to see if people are sending bad queries based on objectClass but if you have a directory of any size and you are using any LDAP aware apps, you are probably getting hit with inefficient queries based on objectClass. So just do it. You are going to do it down the road anyway… More on that later.

So how do you index objectClass? Its easy.

The following command run from a schema admin account will do the work for you:

adfind -schema -f name=object-class searchFlags -adcsv | admod searchFlags::{{.:set:1}} -exterr

That command finds the DN and current searchFlags values for the class definition and then lights up bit 0 (value 1) which tells it to index the attribute. Cool huh? And you thought schema changes were tough…

Example:

F:\>adfind -schema -f name=object-class searchFlags -adcsv
~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~
“dn”,”searchFlags”
“CN=Object-Class,CN=Schema,CN=Configuration,DC=joe,DC=com”,“8”

F:\>adfind -schema -f name=object-class searchFlags -adcsv | admod searchFlags::{{.:set:1}} -exterr

AdMod V01.10.00cpp Joe Richards (joe@joeware.net) February 2007

DN Count: 1
Using server: 2k3dc11.joe.com:389
Directory: Windows Server 2003

Modifying specified objects…
DN: CN=Object-Class,CN=Schema,CN=Configuration,DC=joe,DC=com…

The command completed successfully

As an aside, you will note that I didn’t target a specific domain controller for this update… In other words, I didn’t target the schema master… You will also note there was no error message… “So what” you say, “2k3dc11 must be your schema master, you got lucky…” No, 2k3dc11 isn’t my Schema Master, 2k3dc02 is. This is the magic of something called the LDAP Write Referral. What happens is the DC that I hit, 2k3dc11, knew it wasn’t able to write that value I needed written so it sent back a Write Referral to my machine telling me which server to contact to make that change. My application, like most, by default, will chase the referral and execute the command on the schema master refereed to by the first DC.

This is important functionality to keep in mind because once you start running Longhorn and you decide to deploy Read Only DCs (RODC) this will almost certainly crop up with normal object updates. By default, RODCs will refer all write requests to a full DC since they aren’t allowed to accept updates. This could be a problem if you aren’t aware of it. Any apps you have that write an update and then look at the directory immediately after will get confused because the update won’t be on the DC they thought they wrote it to. Depending on the app, different things will occur. You need to test test test test any apps that you have that will need to run against RODCs.

To illustrate this issue, right after I made the update above, I ran another query to check that the value was written properly:

F:\>adfind -sc s:objectclass searchFlags -adcsv
~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~
“dn”,”searchFlags”
“CN=Object-Class,CN=Schema,CN=Configuration,DC=joe,DC=com”,“8 [PRESERVE TOMBSTONE(8)]”

Note that the value didn’t change… Oh my! It didn’t work… No, not quite, give it a few moments for replication to complete and voila:

F:\>adfind -sc s:objectclass searchFlags -adcsv
~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~~~~ADCSV~~~
“dn”,”searchFlags”
“CN=Object-Class,CN=Schema,CN=Configuration,DC=joe,DC=com”,“9 [INDEX(1);PRESERVE TOMBSTONE(8)]”

This isn’t a problem, it is how it HAS to work. Just be aware of it and if you write programs for Active Directory, keep that in mind and write your programs accordingly. There are programmatic ways to ask for Writeable DCs.

 

So now that the schema change is replicated, you will want to make sure you are working with the refreshed schema. If you aren’t going to use the changes right away this isn’t necessary because the schema cache will refresh itself. Usually though, when you make a change, you want to test it right away, so you want to force an immediate schema cache refresh. I personally use admod to refresh the schema with the command

admod -sc refreshschema

 

So the next question is…. Is that small change worth it? YES! Here is an example from the test directory that I updated. First a user query across the entire domain with objectclass in its natural Windows 2000/Server 2003 state.

F:\>adfind -default -f objectclass=user -dn -stats+only

AdFind V01.37.00cpp Joe Richards (joe@joeware.net) March 2007

Using server: 2k3dc11.joe.com:389
Directory: Windows Server 2003
Base DN: DC=joe,DC=com

Statistics
=================================
Elapsed Time: 110 (ms)
Returned 17308 entries of 40434 visited – (42.81%)

Used Filter:
(objectClass=user)

Used Indices:
DNT_index:13183:N

Analysis
———————————
Hit Rate of 42.81% is Ok

No dedicated indices used for search, this is inefficient.

Indices used:

Index Name : DNT_index
Record Count: 13183 (estimate)
Index Type : Normal Attribute Index

Filter Breakdown:

(objectClass=user)

And after objectClass is indexed and the index has had a chance to build…

F:\>adfind -default -f objectclass=user -dn -stats+only

AdFind V01.37.00cpp Joe Richards (joe@joeware.net) March 2007

Using server: 2k3dc11.joe.com:389
Directory: Windows Server 2003
Base DN: DC=joe,DC=com

Statistics
=================================
Elapsed Time: 20 (ms)
Returned 17308 entries of 20339 visited – (85.10%)

Used Filter:
(objectClass=user)

Used Indices:
idx_objectClass:19117:N

Analysis
———————————
Hit Rate of 85.10% is Efficient

Indices used:

Index Name : idx_objectClass
Record Count: 19117 (estimate)
Index Type : Normal Attribute Index

Filter Breakdown:

(objectClass=user)

 

Sound good?

So previously I mentioned that you will eventually end up doing this anyway right? Well Microsoft FINALLY has built this into the schema on Longhorn. You can see it for yourself, and in fact I really encourage you to, by going out to MSDN and downloading the February CTP of Longhorn (you DO have an MSDN subscription don’t you? If not, why not?). Once you have Longhorn loaded up (I run it on Virtual Server in 16GB disk configurations with 512MB of RAM allocated and it works great) run through the new DC Promo dialog and fire it up. Assuming you don’t have a bunch of weird apps running on your Domain Controllers, you will likely have Longhorn out on your DCs before you have Vista deployed to a majority of your clients. If you have branch DCs the RODC helps with so many issues with those kinds of deployments, couple that with the other security upgrades and the granular password policy and Longhorn for domain controllers is really going to be a must have for many companies.

  joe

Rating 3.00 out of 5

3 Responses to “Searching for users with the LDAP Filter (objectClass=user)…”

  1. Mike.Kline says:

    This one is a keeper!! Good article Joe. At this point everyone should be using (&(objectCategory=person)(objectClass=user)) because when a question comes up on the lists you or Jorge or another MVP will tell the person about it.

    One of the problems I have seen is with two words “schema change”. People are so fearful of any change to the schema and even for small things like this.

  2. luke says:

    Do you know why the objectClass index was excluded from Windows Server 2003? You can almost understand it not being included in the Win2k RTM? Surely there has to be a reasonable explanation for not including it in Windows Server 2003?

  3. joe says:

    Mike: Yes I have posted that A LOT over the last 7 or so years…

    Luke: No clue, the only thing I can think of is that they just didn’t want to rock the boat at the time.

[joeware – never stop exploring… :) is proudly powered by WordPress.]