Search code examples
c#asp.net-corepostmanasp.net-core-webapi

ASP.Net Core API failing when I try to return results from Active Directory search and some values are empty


using Microsoft.AspNetCore.Mvc;
using System.DirectoryServices;
using System.Security.Principal;
using Newtonsoft.Json;

namespace SDAdmConsole.Controllers;

[ApiController]
[Route("api/[controller]")]
public class SearchUsrController : Controller
{
    public IActionResult  Index()
    {
        // List of Domains to Check users
        string[] domains = { "tst-ads-001", "tst-ads-001." };
        
        // Active Directory Properties we need to bring the results for
        string[] propertiesToLoad = { "samAccountName", "displayName", "objectSid", "department", "employeeNumber", "manager", "userPrincipalName","badPwdCount", "lockoutTime", 
                                    "lastLogon", "lastLogonTimestamp", "pwdLastSet", "homeDirectory", "extensionAttribute1", "distinguishedName", "userWorkstations" 
                                    };
        
        // Master Credentials for Active Directory LDAP search
        string domainUser = "redacted";
        string domainPassword = "redacted";

        // Filter used for Active Directory Search
        string searchQuery = "(&(objectCategory=user)(objectClass=user)(samAccountName=*steven.test*))";
        
        // New empty Dictionary to put all the results returned into.
        List<Dictionary<string, object>> resultList = new List<Dictionary<string, object>>();

        // Search each domain in the list of Domains
        foreach (string domain in domains)
        {
            // New Search builder
            DirectorySearcher searcher = new DirectorySearcher(new DirectoryEntry("LDAP://" + domain, domainUser, domainPassword), searchQuery, propertiesToLoad);

            // Results returned as a collection
            SearchResultCollection results = searcher.FindAll();

            foreach (SearchResult result in results)
            {
                // Create Dictionary to store all the values from each user found
                Dictionary<string, object> resultDict = new Dictionary<string, object>();

                // Convert raw SID in to a readable value
                byte[] sidBytes = (byte[])result.Properties["objectSid"][0];
                SecurityIdentifier sid = new SecurityIdentifier(sidBytes, 0);
                string sidString = sid.Value;               
            
                resultDict.Add("displayName", result.Properties["displayName"][0]);
                resultDict.Add("sAMAccountName", result.Properties["sAMAccountName"][0]); 
                resultDict.Add("department", result.Properties["department"][0]);   
                resultDict.Add("employeeNumber", result.Properties["employeeNumber"][0]);   
                resultDict.Add("manager", result.Properties["manager"][0]);   
                resultDict.Add("userPrincipalName", result.Properties["userPrincipalName"][0]);   
                resultDict.Add("badPwdCount", result.Properties["badPwdCount"][0]);
                resultDict.Add("lockoutTime", result.Properties["lockoutTime"][0]);
                resultDict.Add("lastLogon", result.Properties["lastLogon"][0]);   
                resultDict.Add("lastLogonTimestamp", result.Properties["lastLogonTimestamp"][0]);   
                resultDict.Add("pwdLastSet", result.Properties["pwdLastSet"][0]);
                resultDict.Add("homeDirectory", result.Properties["homeDirectory"][0]); 
                resultDict.Add("objectSid", sidString);
                //resultDict.Add("extensionAttribute1", result.Properties["extensionAttribute1"][0]);   
                //resultDict.Add("distinguishedName", result.Properties["distinguishedName"][0]); 
                //resultDict.Add("userWorkstations", result.Properties["userWorkstations"][0]); 
                //resultDict.Add("extensionAttribute1", result.Properties["extensionAttribute1"][0]);   
                //resultDict.Add("mail", result.Properties["mail"][0]);
                //resultDict.Add("memberof", result.Properties["memberof"][0]);   */                      
                resultList.Add(resultDict);
            }
        }

        // Convert Dictionary in to JSON array
        string json = JsonConvert.SerializeObject(resultList);

        // Return JSON List for the API request
        return Ok(json);
    }
}

The API works great if all of the properties returned have values in them. If any of them have an empty value, for example no home folder, the API request fails and returns the homepage html instead. There are no errors when compiling so I'm not sure what else to try.

I tried an if and else statement to say if the value is empty or null then put this string in place but still fails.

Any advice would be great thank you


Solution

  • I can assume that the error happens because you are trying to refer to an item in the collection by an index that doesn't exist. This can cause the application to throw an IndexOutOfRangeException. Or possibly the collection is null and then a NullReferenceException will be thrown.

    The solution could be to use conditional operators and null-conditional operators:

    var resultDict = new Dictionary<string, object>();
    resultDict.Add("displayName", result.Properties["displayName"]?.Count > 0 ? result.Properties["displayName"][0] : "");
    resultDict.Add("sAMAccountName", result.Properties["sAMAccountName"]?.Count > 0 ? result.Properties["sAMAccountName"][0] : "");
    resultDict.Add("department", result.Properties["department"]?.Count > 0 ? result.Properties["department"][0] : "");
    resultDict.Add("employeeNumber", result.Properties["employeeNumber"]?.Count > 0 ? result.Properties["employeeNumber"][0] : "");
    resultDict.Add("manager", result.Properties["manager"]?.Count > 0 ? result.Properties["manager"][0] : "");
    resultDict.Add("userPrincipalName", result.Properties["userPrincipalName"]?.Count > 0 ? result.Properties["userPrincipalName"][0] : "");
    resultDict.Add("badPwdCount", result.Properties["badPwdCount"]?.Count > 0 ? result.Properties["badPwdCount"][0] : 0);
    resultDict.Add("lockoutTime", result.Properties["lockoutTime"]?.Count > 0 ? result.Properties["lockoutTime"][0] : 0);
    resultDict.Add("lastLogon", result.Properties["lastLogon"]?.Count > 0 ? result.Properties["lastLogon"][0] : 0);
    resultDict.Add("lastLogonTimestamp", result.Properties["lastLogonTimestamp"]?.Count > 0 ? result.Properties["lastLogonTimestamp"][0] : 0);
    resultDict.Add("pwdLastSet", result.Properties["pwdLastSet"]?.Count > 0 ? result.Properties["pwdLastSet"][0] : 0);
    resultDict.Add("homeDirectory", result.Properties["homeDirectory"]?.Count > 0 ? result.Properties["homeDirectory"][0] : "");
    resultDict.Add("objectSid", sidString);
    // other properties if needed
    resultList.Add(resultDict);
    

    This code will add empty strings or 0 values for absent properties. You can choose your own "no value" value.

    If you want to avoid adding missing values to the dictionary altogether, instead of adding items with empty strings or zeros, you should check the values before each insertion:

    if (result.Properties["displayName"]?.Count > 0)
        resultDict.Add("displayName", result.Properties["displayName"][0]);
    if (result.Properties["sAMAccountName"]?.Count > 0)
        resultDict.Add("sAMAccountName", result.Properties["sAMAccountName"][0]);
    if (result.Properties["department"]?.Count > 0)
        resultDict.Add("department", result.Properties["department"][0]);
    if (result.Properties["employeeNumber"]?.Count > 0)
        resultDict.Add("employeeNumber", result.Properties["employeeNumber"][0]);
    if (result.Properties["manager"]?.Count > 0)
        resultDict.Add("manager", result.Properties["manager"][0]);
    if (result.Properties["userPrincipalName"]?.Count > 0)
        resultDict.Add("userPrincipalName", result.Properties["userPrincipalName"][0]);
    if (result.Properties["badPwdCount"]?.Count > 0)
        resultDict.Add("badPwdCount", result.Properties["badPwdCount"][0]);
    if (result.Properties["lockoutTime"]?.Count > 0)
        resultDict.Add("lockoutTime", result.Properties["lockoutTime"][0]);
    if (result.Properties["lastLogon"]?.Count > 0)
        resultDict.Add("lastLogon", result.Properties["lastLogon"][0]);
    if (result.Properties["lastLogonTimestamp"]?.Count > 0)
        resultDict.Add("lastLogonTimestamp", result.Properties["lastLogonTimestamp"][0]);
    if (result.Properties["pwdLastSet"]?.Count > 0)
        resultDict.Add("pwdLastSet", result.Properties["pwdLastSet"][0]);
    if (result.Properties["homeDirectory"]?.Count > 0)
        resultDict.Add("homeDirectory", result.Properties["homeDirectory"][0]);
    resultDict.Add("objectSid", sidString);