using DigitalData.Core.Contracts.Application; using DigitalData.UserManager.Application.Contracts; using DigitalData.UserManager.Application.DTOs; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Caching.Memory; using System.Diagnostics.CodeAnalysis; using System.Security.Claims; using DigitalData.UserManager.Application; using DigitalData.UserManager.Application.DTOs.User; using System.DirectoryServices; using static System.Runtime.InteropServices.JavaScript.JSType; using System.Linq; using System.IO; namespace DigitalData.UserManager.API.Controllers { [Route("api/[controller]")] [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "")] public class DirectoryController : ControllerBase { private ILogger _logger; private IUserService _userService; private IDirectorySearchService _dirSearchService; private IMemoryCache _memoryCache; private Dictionary _customSearchFilters; public DirectoryController(IConfiguration configuration, ILogger logger, IUserService userService, IDirectorySearchService directorySearchService, IMemoryCache memoryCache) { _logger = logger; _userService = userService; _dirSearchService = directorySearchService; _memoryCache = memoryCache; var customSearchFiltersSection = configuration.GetSection("DirectorySearch:CustomSearchFilters"); _customSearchFilters = customSearchFiltersSection.Get>() ?? new(); } [HttpGet("Root/{username}")] public IActionResult GetRootOf(string username) { var root = _dirSearchService.GetSearchRootCache(username); return root is null ? NotFound() : Ok(new { guid = root.Guid, nativeGuid = root.NativeGuid, name = root.Name, path = root.Path, parentPath = root.Parent?.Path, username = root.Username, schemaClassName = root.SchemaClassName }); } [HttpGet("CustomSearchFilter")] public IActionResult GetAllCustomFilters(string? filtername) { if (filtername is null) { return Ok(_customSearchFilters); } else { _dirSearchService.CustomSearchFilters.TryGetValue(filtername, out string? filter); return filter is null ? NotFound() : Ok(filter); } } [HttpPost("CreateSearchRoot")] public async Task CreateSearchRoot([FromBody] SearchRootCreateDto searchRootCreateDto) { var dirEntryUsername = searchRootCreateDto.DirEntryUsername ?? CurrentUser; if (dirEntryUsername is null) return Unauthorized(); bool isValid = _dirSearchService.ValidateCredentials(dirEntryUsername, searchRootCreateDto.DirEntryPassword); if (!isValid) return Unauthorized(_dirSearchService.Failed(MessageKey.UserNotFound.ToString())); var userResult = await _userService.ReadByUsernameAsync(dirEntryUsername); if(!userResult.IsSuccess || userResult.Data is null) return Unauthorized(_dirSearchService.Failed(MessageKey.UserNotFoundInLocalDB.ToString())); _dirSearchService.SetSearchRootCache(userResult.Data.Username, searchRootCreateDto.DirEntryPassword); return Ok(); } [HttpGet("SearchByFilter/{filter}")] public IActionResult SearchByFilter([FromRoute] string filter, string? dirEntryUsername, params string[] propName) { dirEntryUsername ??= CurrentUser; if (dirEntryUsername is null) return Unauthorized(); var result = _dirSearchService.FindAllByUserCache(dirEntryUsername, filter, properties: propName); return Ok(result); } [HttpGet("SearchByFilterName/{filterName}")] public IActionResult SearchByFilterName([FromRoute] string filterName, string? dirEntryUsername, params string[] propName) { dirEntryUsername ??= CurrentUser; if (dirEntryUsername is null) return Unauthorized(); _dirSearchService.CustomSearchFilters.TryGetValue(filterName, out string? filter); if (filter is null) return NotFound($"The filter named {filterName} does not exist."); var result = _dirSearchService.FindAllByUserCache(dirEntryUsername, filter, properties: propName); return Ok(result); } [HttpGet("Group")] public IActionResult GetGroups(string? dirEntryUsername, params string[] propName) { dirEntryUsername ??= CurrentUser; if (dirEntryUsername is null) return Unauthorized(); _dirSearchService.CustomSearchFilters.TryGetValue("Group", out string? filter); if (filter is null) throw new InvalidOperationException("The LDAP Group Search filter configuration is missing in your appsettings. Please ensure it's added under DirectorySearch:CustomSearchFilters:Group to enable group searches."); var result = _dirSearchService.FindAllByUserCache(username: dirEntryUsername, filter, properties: propName); return Ok(result); } [HttpGet("User")] public IActionResult GetUsersByGroupName(string? dirEntryUsername, [FromQuery] string? groupName = null) { string[] propName = { "memberof", "samaccountname", "givenname", "sn", "mail" }; dirEntryUsername ??= CurrentUser; if (dirEntryUsername is null) return Unauthorized(); _dirSearchService.CustomSearchFilters.TryGetValue("User", out string? filter); if (filter is null) throw new InvalidOperationException("The LDAP User Search filter configuration is missing in your appsettings. Please ensure it's added under DirectorySearch:CustomSearchFilters:User to enable group searches."); var result = _dirSearchService.FindAllByUserCache(username: dirEntryUsername, filter, properties: propName); if (groupName is not null && result.IsSuccess && result.Data is not null) result.Data = result.Data .Where(rp => rp.PropertyNames.Cast().Contains("memberof") && rp["memberof"].Cast().Any(ldapDir => ldapDir.Contains(groupName))) .ToList(); return Ok(result); } private string? CurrentUser { get => (HttpContext.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value); } } }