views:

437

answers:

1

Given a NT style account name (DOMAIN\UserName) is it possible to infer what the LDAP address for that domain is so that user info can be looked up?

My scenario: I have an asp.net app running on IIS that accepts both anonymous and domain users. The anonymous users have to sign in but the domain users I check the server headers for the domain user name provided by IIS. I need to look up some info from active directory like email address etc. I have got this working if I supply the LDAP address in config but would prefer not to have to maintain this extra config value if I can avoid it.

+3  A: 

If all of the domains are part of the same forest, you should be able to do a global catalog seach (GC:// instead of LDAP://). You only get a partial attribute set back but you can get the distinguishedName and then to a standard LDAP:// lookup.

If you're in the situation where you have different domains that are in different forests, then one simple way would be to build a look-up table of your NetBIOS domain names. For each forest, you do a subtree search of CN=Partitions,CN=Configuration,DC=YourDomain,DC=com with a filter of (netBIOSname=*) and you'll get back a list of the domains in that forest. The dnsRoot attribute will give you the DNS name of the domain and you can just use that to bind to, or do a DNS lookup of it and use the first address you get to bind to. Or you can use the dnsRoot to create System.DirectoryServices.ActiveDirectory.DirectoryContext to with a DirectoryContextType of DirectoryServer to get you a reference to the domain controller. Or you could use nCName (gives you the namingContext of the domain).

I can probably help more, if you can provide more details, or if any of that wasn't clear.

Additional:

  1. You can get a DirectoryEntry by doing a 'serverless bind' by just supplying the distinguishedName of an object in the directory. E.g. "LDAP://CN=User1,CN=Users,DC=yourdomain,DC=com". This will discover the appropriate domain controller automatically and bind to it to get the object.
  2. If you're doing a search using DirectorySearcher, and you don't supply a SearchRoot object it will automatically bind to the root of the current domain. You can provide a SearchRoot to narrow down the search but you don't have to.
  3. If you absolutely need to get the name of the current domain, you can bind to an object called RootDSE ("LDAP://RootDSE") and get the value of the defaultNamingContext attribute. This will return the "DC=yourdomain,DC=com" bit.

Frankly, more general code is probably not worth the pain unless you're sure you're going to need it because it will be dependent on the structure of your domains and forests. E.g. if you have two forests, is there a trust between them: you won't know this until you have two forests and the solution will depend on this. There's a pithy little maxim in agile development which escapes me but it goes along the lines of don't code what you don't need now.

Here's a console program that will perform such a search:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.DirectoryServices;

namespace SearchDirectory
{
    class Program
    {
        static void Main(string[] args)
        {
            string user = @"YOURDOMAIN\yourid";

            using (DirectorySearcher ds = new DirectorySearcher())
            {
                ds.SearchScope = SearchScope.Subtree;
                ds.Filter = String.Format("(&(objectClass=user)(objectCategory=person)(sAMAccountName={0}))",
                    user.Split('\\')[1]);
                ds.PageSize = 1000;
                using (SearchResultCollection src = ds.FindAll())
                {
                    foreach (SearchResult sr in src)
                        Console.WriteLine(sr.Properties["distinguishedName"][0].ToString());
                }
            }

            Console.WriteLine("\r\nPress a key to continue...");
            Console.ReadKey(true);
        }
    }
}

I've cut some corners on this but it should get you started. My advice is to get it working in a console program and then move the class to your ASP.NET project. There are plenty of odd errors System.DirectoryServices can throw you and using S.DS inside of ASP.NET can be fun too so it's best to know your code works before you wrap it in all of that ASP.NET loveliness.

serialhobbyist
I’m not very familiar with domain controllers I’m afraid but I think I understand what you are saying.If I have the netBios name of the forest controller I can use that to look up the LDAP address for the user’s domain.My problem I do not know how to get the address for any of the domain controllers. So I guess my question should be it is infer the netBois name of the domain controller for a machine when user is asp.net user.
Graham Ambrose
Okay. The solution will depend on whether you're dealing with one active directory forest or several: which is it in your case? If it's one forest, is there more than one domain in the forest? Is the ASP.NET server in the domain (or one of the domains/forests)?
serialhobbyist
Be nice to support different set-ups but I have one forest one domain that the ASP.NET server belongs too.
Graham Ambrose
I've added a bit more info and a code sample. If that's not what you're after can you give me a bit more to go on.
serialhobbyist
Thanks a lot, that's a fine looking answer. I was using a search root as I though it was required but with out my code rocks along with out the unnecessary config.
Graham Ambrose
Glad I could help. If you're expecting to do much with DirectoryServices I recommend this book: The .NET Developer's Guide to Directory Services Programming (http://www.amazon.com/gp/product/0321350170). There's not a lot you'll want to do that isn't covered in the book but it's quite accessible.
serialhobbyist