How to Get Domain Users, Search Users, and Get User From Active Directory Using .NET Core API

Introduction 

 
In this sample, I am going to implement the .NET Core API with services, Repository and controller functions. To test it, I am going to use Postman.
 

Active Directory

 
Active Directory saves data as objects. An object is a single element, such as a user, group, application or device, such as a printer. Objects are normally defined as either a resource like printers or computers, or security principals such as users or groups.
 
PrincipalContext Class
 
This is the class used to encapsulate the server or domain against all operations are performed. The container is used as the base of operations, and the credentials areused to perform the operations.
 
UserPrincipal Class
 
The class used to encapsulate principals that are the user accounts.
 
PrincipalSearcher Class
 
Class used to encapsulate the methods and search patterns used to execute a query against the underlying principal store.
 

Getting Started .NET Core API

  • Start Visual Studio 2019
  • Create a new project.
  • Choose ASP.NET Core Web Application.
  • Choose the Web Application template and keep the default project name and location. In the dropdown with the ASP.NET Core version.
  • Choose API and select version ASP.NET Core 2.1 or ASP.NET Core 3.1.
  • Click Create.
Let’s add a model class.
 
AddUser class
  1. public class AdUser {  
  2.     public DateTime ? AccountExpirationDate {  
  3.         get;  
  4.         set;  
  5.     }  
  6.     public DateTime ? AccountLockoutTime {  
  7.         get;  
  8.         set;  
  9.     }  
  10.     public int BadLogonCount {  
  11.         get;  
  12.         set;  
  13.     }  
  14.     public string Description {  
  15.         get;  
  16.         set;  
  17.     }  
  18.     public string DisplayName {  
  19.         get;  
  20.         set;  
  21.     }  
  22.     public string DistinguishedName {  
  23.         get;  
  24.         set;  
  25.     }  
  26.     public string Domain {  
  27.         get;  
  28.         set;  
  29.     }  
  30.     public string EmailAddress {  
  31.         get;  
  32.         set;  
  33.     }  
  34.     public string EmployeeId {  
  35.         get;  
  36.         set;  
  37.     }  
  38.     public bool ? Enabled {  
  39.         get;  
  40.         set;  
  41.     }  
  42.     public string GivenName {  
  43.         get;  
  44.         set;  
  45.     }  
  46.     public Guid ? Guid {  
  47.         get;  
  48.         set;  
  49.     }  
  50.     public string HomeDirectory {  
  51.         get;  
  52.         set;  
  53.     }  
  54.     public string HomeDrive {  
  55.         get;  
  56.         set;  
  57.     }  
  58.     public DateTime ? LastBadPasswordAttempt {  
  59.         get;  
  60.         set;  
  61.     }  
  62.     public DateTime ? LastLogon {  
  63.         get;  
  64.         set;  
  65.     }  
  66.     public DateTime ? LastPasswordSet {  
  67.         get;  
  68.         set;  
  69.     }  
  70.     public string MiddleName {  
  71.         get;  
  72.         set;  
  73.     }  
  74.     public string Name {  
  75.         get;  
  76.         set;  
  77.     }  
  78.     public bool PasswordNeverExpires {  
  79.         get;  
  80.         set;  
  81.     }  
  82.     public bool PasswordNotRequired {  
  83.         get;  
  84.         set;  
  85.     }  
  86.     public string SamAccountName {  
  87.         get;  
  88.         set;  
  89.     }  
  90.     public string ScriptPath {  
  91.         get;  
  92.         set;  
  93.     }  
  94.     public SecurityIdentifier Sid {  
  95.         get;  
  96.         set;  
  97.     }  
  98.     public string Surname {  
  99.         get;  
  100.         set;  
  101.     }  
  102.     public bool UserCannotChangePassword {  
  103.         get;  
  104.         set;  
  105.     }  
  106.     public string UserPrincipalName {  
  107.         get;  
  108.         set;  
  109.     }  
  110.     public string VoiceTelephoneNumber {  
  111.         get;  
  112.         set;  
  113.     }  
  114. }  
Here is my AdUserProvider class:
  1. public class AdUserProvider: IUserProvider {  
  2.         public AdUser CurrentUser {  
  3.             get;  
  4.             set;  
  5.         }  
  6.         public bool Initialized {  
  7.             get;  
  8.             set;  
  9.         }  
  10.         public async Task Create(HttpContext context, IConfiguration config) {  
  11.             CurrentUser = await GetAdUser(context.User.Identity);  
  12.             Initialized = true;  
  13.         }  
  14.         public Task < AdUser > GetAdUser(IIdentity identity) {  
  15.             return Task.Run(() => {  
  16.                 try {  
  17.                     PrincipalContext context = new PrincipalContext(ContextType.Domain);  
  18.                     UserPrincipal principal = new UserPrincipal(context);  
  19.                     if (context != null) {  
  20.                         principal = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, identity.Name);  
  21.                     }  
  22.                     return AdUser.CastToAdUser(principal);  
  23.                 } catch (Exception ex) {  
  24.                     throw new Exception("Error retrieving AD User", ex);  
  25.                 }  
  26.             });  
  27.         }  
  28.         public Task < AdUser > GetAdUser(string samAccountName) {  
  29.             return Task.Run(() => {  
  30.                 try {  
  31.                     PrincipalContext context = new PrincipalContext(ContextType.Domain);  
  32.                     UserPrincipal principal = new UserPrincipal(context);  
  33.                     if (context != null) {  
  34.                         principal = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, samAccountName);  
  35.                     }  
  36.                     return AdUser.CastToAdUser(principal);  
  37.                 } catch (Exception ex) {  
  38.                     throw new Exception("Error retrieving AD User", ex);  
  39.                 }  
  40.             });  
  41.         }  
  42.         public Task < AdUser > GetAdUser(Guid guid) {  
  43.             return Task.Run(() => {  
  44.                 try {  
  45.                     PrincipalContext context = new PrincipalContext(ContextType.Domain);  
  46.                     UserPrincipal principal = new UserPrincipal(context);  
  47.                     if (context != null) {  
  48.                         principal = UserPrincipal.FindByIdentity(context, IdentityType.Guid, guid.ToString());  
  49.                     }  
  50.                     return AdUser.CastToAdUser(principal);  
  51.                 } catch (Exception ex) {  
  52.                     throw new Exception("Error retrieving AD User", ex);  
  53.                 }  
  54.             });  
  55.         }  
  56.         public Task < List < AdUser >> GetDomainUsers() {  
  57.             return Task.Run(() => {  
  58.                 PrincipalContext context = new PrincipalContext(ContextType.Domain);  
  59.                 UserPrincipal principal = new UserPrincipal(context);  
  60.                 principal.UserPrincipalName = "*@*";  
  61.                 principal.Enabled = true;  
  62.                 PrincipalSearcher searcher = new PrincipalSearcher(principal);  
  63.                 var users = searcher.FindAll().Take(50).AsQueryable().Cast < UserPrincipal > ().FilterUsers().SelectAdUsers().OrderBy(x => x.Surname).ToList();  
  64.                 return users;  
  65.             });  
  66.         }  
  67.         public Task < List < AdUser >> FindDomainUser(string search) {  
  68.             return Task.Run(() => {  
  69.                 PrincipalContext context = new PrincipalContext(ContextType.Domain);  
  70.                 UserPrincipal principal = new UserPrincipal(context);  
  71.                 principal.SamAccountName = $ "*{search}*";  
  72.                 principal.Enabled = true;  
  73.                 PrincipalSearcher searcher = new PrincipalSearcher(principal);  
  74.                 var users = searcher.FindAll().AsQueryable().Cast < UserPrincipal > ().FilterUsers().SelectAdUsers().OrderBy(x => x.Surname).ToList();  
  75.                 return users;  
  76.             });  
  77.         }  
As you can see in get domain users, I am fetching only 50 users because my active directory has thousands on users, that takes long time to get the data.
 
IUserProvider interface
  1. public interface IUserProvider {  
  2.     AdUser CurrentUser {  
  3.         get;  
  4.         set;  
  5.     }  
  6.     bool Initialized {  
  7.         get;  
  8.         set;  
  9.     }  
  10.     Task Create(HttpContext context, IConfiguration config);  
  11.     Task < AdUser > GetAdUser(IIdentity identity);  
  12.     Task < AdUser > GetAdUser(string samAccountName);  
  13.     Task < AdUser > GetAdUser(Guid guid);  
  14.     Task < List < AdUser >> GetDomainUsers();  
  15.     Task < List < AdUser >> FindDomainUser(string search);  
  16. }  
Now let’s work on controller part.
 
Here is my controller code:
 
ADController
  1. using MapAPI.Identity;  
  2. using Microsoft.AspNetCore.Authorization;  
  3. using Microsoft.AspNetCore.Mvc;  
  4. using System.Collections.Generic;  
  5. using System.Threading.Tasks;  
  6. namespace MapAPI.Controllers {  
  7.     [Authorize]  
  8.     [Route("api/[controller]")]  
  9.     [ApiController]  
  10.     public class ADController: ControllerBase {  
  11.         IUserProvider userProvider;  
  12.         public ADController(IUserProvider _userProvider) {  
  13.                 userProvider = _userProvider;  
  14.             }  
  15.             [HttpGet("[action]")]  
  16.         public async Task < List < AdUser >> GetDomainUsers() => await userProvider.GetDomainUsers();  
  17.         [HttpGet("[action]/{search}")]  
  18.         public async Task < List < AdUser >> FindDomainUser([FromRoute] string search) => await userProvider.FindDomainUser(search);  
  19.         [HttpGet("[action]")]  
  20.         public AdUser GetCurrentUser() => userProvider.CurrentUser;  
  21.     }  
  22. }  
We are all set now! Let’s run the application and hit the endpoints to see the output.
 
List of domain Users
 
 
Search user by id from AD
 
 
 
 
Get current user data from AD
 
 

Conclusion

 
In this article, we saw how to implement .NET core API and get data from Windows Active Directory.