CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Peter's Gekko

public Blog MyNotepad : Imho { }

Getting information out of active directory: DirectorySearcher, Properties and DirectoryEntry

One of my apps needed to get some information out of ActiveDirectory. The 2.0 framework does contain some very nice classes to help. Getting these to work as intended took some trouble; so I'll recapitulate in public.

The scenario: the user can log in from anywhere, not necessarily from within the domain, and provides his username and password credentials (note the security risk of a password travelling over a potentially insecure wire). It's up to the webapp to check if the user is a valid member of the (Active Directory) domain and which group s/he is a member off. The web server on which the app is running is a member of the domain.

The DirectorySearcher class provides all AD info. Use it's Filter property to select the AD entries. The FindOne method will return the first entry matching, the FindAll method returns all entries. After invoking the method the Properties of the search result contain all AD properties.

DirectorySearcher ds = new DirectorySearcher();

ds.Filter = "samaccountname=" + userName;

SearchResult sr = ds.FindOne();

   

System.Text.StringBuilder sb = new System.Text.StringBuilder();

foreach (string var in sr.Properties.PropertyNames)

    sb.AppendLine(string.Format("{0} : {1}", var, sr.Properties[var][0].ToString()));

this first shot returns most AD info. An example of the result in IE

That are quite a lot of properties. You can restrict the number of properties returned by filling the PropertiesToLoad collection of the DirectorySearcher object. Another thing to watch is that some properties are a collection on itself. Take the memberof property. It's a list of the groups the user is a member off. Precisely the info I needed. A better shot would be:

DirectorySearcher ds = new DirectorySearcher();

ds.Filter = "samaccountname=" + userName;

ds.PropertiesToLoad.Add("memberof");

SearchResult sr = ds.FindOne();

   

System.Text.StringBuilder sb = new System.Text.StringBuilder();

foreach (string var in sr.Properties.PropertyNames)

{

    for (int i=0; i < sr.Properties[var].Count; i++)

                    sb.AppendLine(string.Format("{0}-{1} : {2}", var, i, sr.Properties[var]Idea.ToString()));

}

Now the code provides me exactly the info I need.

Note that you can read all this information without a valid password for the user. To validate the user password you need a DirectoryEntry object. This can be created straight from the search result. After setting the Password property you have to bind to the native underlying AD Com object to validate the password.

DirectoryEntry adsEntry = sr.GetDirectoryEntry();

adsEntry.Password = passWord;

try

{

object o = adsEntry.NativeObject;

}

catch (DirectoryServicesCOMException ex)

{

adError = ex.Message;

}

In case the password is invalid this will result in a clear message "Logon failure: unknown user name or bad password".

In the end this looks quite simple. What really got me on the wrong track is that the internal name of the AD properties does not always match the name as it is displayed in the AD management console. For instance there no Last Name property, only a sn property. I had to find out the property names by enumerating the PropertyNames collection; I could not find any resource which map the display names on the internal names. Another thing is that for a domain user who is not part of any internal domain group, but only of an external group, the member of collection is empty and as a result the memberOf property is not even returned.

It took some patience…


Published Dec 12 2006, 04:58 AM by pvanooijen
Filed under:

Comments

pvanooijen said:

Thanks for the link.

There is an interesting article in the MS knowledge base on the primary group here

http://support.microsoft.com/kb/321360

The primary group does not have to be a member of the domain, even in a single domain scenario. And will not show up when enumerating the groups

# December 13, 2006 4:34 AM

Peter's Gekko said:

In my last post I described some of my troubles working with Active directory entries from code. Here&#39;s

# December 14, 2006 4:49 AM

zullu said:

Hi Peter,

Can You guide me to the step by step method to create this AD Lookup Web Service.

I need to display the User and his Managre's detail on a form by connecting to this web service.

Thanks in advance for your help.

Zullu

# May 31, 2007 12:22 PM

Peter's Gekko said:

Some time ago I wrote a post on getting information out of Active Directory programmatically . You can

# June 22, 2007 5:23 AM

Chaz said:

Is it possible to extract the user's password from the directory entry?

# June 25, 2007 11:47 AM

pvanooijen said:

:)

That would be nice, wouldn't it ? No, it.s not in the list of properties. Also in the server admin tools an administrator can reset a password but never read it.

# June 25, 2007 2:26 PM

João Mendes said:

Hi, i've something like that but i've a problem. This works fine at my computer and at staging, but doesn't in the server.

My code is:

DirectoryEntry rootEntry = new DirectoryEntry(ConfigurationSettings.AppSettings["ActiveDirectoryPath"], ConfigurationSettings.AppSettings["ADUser"], ConfigurationSettings.AppSettings["ADPassword"]);

DirectorySearcher search = new DirectorySearcher(rootEntry);

search.PropertiesToLoad.Add("numColaborador");

search.Filter = "(|(cn=" + tokens[1] + ")(sAMAccountName=" + tokens[1] + "))";

SearchResult result = search.FindOne();

collaboratorNum = search.FindOne().GetDirectoryEntry().Properties["numColaborador"].Value as string;

and the error is "The authentication mechanism is unknown."

I read, that can be resolved changing the file machine.config. The attribute userName of processModel tag, must be "machine" and now is "system". But i won't change that because that applies to all sites at the server, and i don't know how they work with teh changes.

Any suggestions?

# September 11, 2007 5:53 AM

Peter's Gekko said:

In a recent post I described some of the basics of retrieving Active Directory information from code

# September 25, 2007 3:51 PM

pvanooijen said:

@Joao

That's hard to say. I would try the overload of the DirectoryEntry which takes an AUthenticateionType and try that.

But I have no personal experiende with that

# September 25, 2007 3:57 PM

Gagandeep Sawant said:

This was the best resolution I encountered for accessing and checking AD. The best part is that it is the fastest of all the availbale solutions.

# April 2, 2008 2:17 PM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add
Check out Devlicio.us!