4
votes

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.

1
What do you mean by LDAP Address? The Address (hostname) for the LDAP server?Freddy
Is it that you have more than one domain that the user could be in and the domains are in different Active Directory forests?serialhobbyist

1 Answers

4
votes

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.