Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

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][i].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…

This entry was posted in Coding. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Mustafa

    I don’t understand anything. Could you post a complete “Sub” or something like that?

  • Juan Carlos

    thanks a lot! this post help me improving my code. great job! thanks again

  • Lizzy

    I’m a beginner.It’s difficult for me!

  • http://www.freewebs.com/ravikantsinghkushwaha Ravi

    I was Hungry for this code

  • http://petersgekko.codebetter.com pvanooijen

    Lockout ? You mean denied access by the admin ?
    That should result in all info returned but a failed login.

  • IbrahimmbI

    What if the user i was validating is lockout how can i handle that

  • marcinsvr

    Peter – good job!
    Helped me a lot, thank you.

  • http://gagansawant.com Gagandeep Sawant

    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.

  • http://codebetter.com/blogs/peter.van.ooijen/ pvanooijen

    @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

  • João Mendes

    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?

  • http://codebetter.com/blogs/peter.van.ooijen/ pvanooijen

    :)

    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.

  • Chaz

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

  • http://codebetter.com/blogs/peter.van.ooijen/ pvanooijen
  • zullu

    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

  • http://codebetter.com/blogs/peter.van.ooijen/ pvanooijen

    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

  • Jason Rastovski

    One thing that you might want to check out is the fact that the “memberof” property doesn’t return the “primary” group that a user belongs to. Do a comparison of which groups a user belongs to, and what the “memberof” retunrs. I remember having to cycle through all the groups to see if the user was a member of the groups…(basically, I had to do it backwards)

    Check out the link below where they discuss the fact that “memberof” doesn’t return the primary group

    http://groups.google.com/group/microsoft.public.active.directory.interfaces/browse_thread/thread/fd1a9fc5a570c93c/d7e965e7b6fa2960%23d7e965e7b6fa2960