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