Search code examples
c#asp.net-coreactive-directoryldap

How to search for users in Active Directory from ASP.NET Core


I don't know how to search for users in Active Directory. This is my current attempt, but I have not run it yet.

public class ADController : Controller
{
    [HttpGet]
    public IActionResult Find()
    {
        return View();
    }

    [HttpPost]
    public IActionResult Find(FindViewModel model)
    {
        DirectoryEntry entry = new DirectoryEntry("LDAP://<full user name>,<Users>,<domain component>");

        DirectorySearcher searcher;
        SearchResultCollection results;

        searcher = new DirectorySearcher(entry);

        searcher.Filter = "(&(objectClass=user)(displayname=*))";
        searcher.SearchScope = SearchScope.Subtree;

        using (searcher)
        {
            results = searcher.FindAll();

            foreach (SearchResult result in results)
            {
                string searchOK = result.Properties["displayname"][0].ToString();
                //objects.Add(searchOK);
            }
        }
        return View();
    }
}
public class FindViewModel
{
    [Display(Name = "UserActiveDirectory")]
    public string UserAD { get; set; }
}

Solution

  • Your requirements are a bit unclear, but I am assuming that:

    1. You want to pass a username to your controller
    2. Find that user in AD,
    3. Pass the displayName of the found user to your view

    If that's the case, then:

    First, since you only need to pass a single string into your controller, there's no benefit to using a class as the parameter. Just use a single string:

    public IActionResult Find(string username)
    

    Then you need to use the username in your filter. There is no attribute called "username", but that most often refers to the sAMAccountName. However it could also refer to the userPrincipalName, which has the format of username@example.com. But I'll assume sAMAccountName.

    Just (objectClass=user) is oddly not enough to limit the search to just user accounts. Computer objects, for example, have an objectClass of user. So if you want to limit the search to only user accounts, you need to also include (objectCategory=person).

    searcher.Filter = $"(&(objectClass=user)(objectCategory=person)(sAMAccountName={username}))";
    

    The SearchScope is Subtree by default, so you don't need this line:

    searcher.SearchScope = SearchScope.Subtree;
    

    You should also use the PropertiesToLoad collection because, if you don't, it will return every attribute. So put only the attributes you plan on using there:

    searcher.PropertiesToLoad.Add("displayName");
    

    Since you're searching by sAMAccountName, which is guaranteed to be unique on the domain, you can use FindOne() instead of FindAll(), since you know there can only be one result (or none).

    var result = searcher.FindOne();
    

    If result is not null, that means the user was found and you can pass the displayName to the view:

    if (result != null) {
        string displayName = (string) result.Properties["displayname"][0];
        return View(displayName);
    }
    

    Otherwise, don't pass anything to the view, and you will have to handle that case in the view.

    Altogether, that looks like this:

    public IActionResult Find(string username)
    {
        var entry = new DirectoryEntry("LDAP://<full user name>,<Users>,<domain component>");
    
        var searcher = new DirectorySearcher(entry) {
            Filter = $"(&(objectClass=user)(objectCategory=person)(sAMAccountName={username}))",
            PropertiesToLoad = { "displayName" }
        };
    
        var result = searcher.FindOne();
        
        if (result != null) {
            string displayName = (string) result.Properties["displayname"][0];
            return View(displayName);
        }
        
        return View();
    }
    

    You may still have to make some updates depending on your actual requirements, but this should get you started.