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 Microsoft.Extensions.Localization; using Microsoft.AspNetCore.Authorization; using DigitalData.Core.Abstraction.Application; using DigitalData.Core.Abstraction.Application.DTO; namespace DigitalData.UserManager.API.Controllers; [Route("api/[controller]")] [SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "")] [Authorize] [Obsolete("Use MediatR")] public class DirectoryController : ControllerBase { private readonly IUserService _userService; private readonly IDirectorySearchService _dirSearchService; private readonly Dictionary _customSearchFilters; private readonly IStringLocalizer _localizer; private readonly ILogger _logger; public DirectoryController(IConfiguration configuration, IStringLocalizer localizer, IUserService userService, IDirectorySearchService directorySearchService, ILogger logger) { _localizer = localizer; _userService = userService; _dirSearchService = directorySearchService; var customSearchFiltersSection = configuration.GetSection("DirectorySearch:CustomSearchFilters"); _customSearchFilters = customSearchFiltersSection.Get>() ?? new(); _logger = logger; } [HttpGet("Root/{username}")] public IActionResult GetRootOf(string username) { try { 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 }); } catch (Exception ex) { _logger.LogError(ex, "{Message}", ex.Message); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("CustomSearchFilter")] public IActionResult GetAllCustomFilters(string? filtername) { try { if (filtername is null) { return Ok(_customSearchFilters); } else { _dirSearchService.CustomSearchFilters.TryGetValue(filtername, out string? filter); return filter is null ? NotFound() : Ok(filter); } } catch (Exception ex) { _logger.LogError(ex, "{Message}", ex.Message); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpPost] public async Task CreateSearchRoot([FromBody] SearchRootCreateDto searchRootCreateDto) { try { var dirEntryUsername = searchRootCreateDto.Username ?? CurrentUser; if (dirEntryUsername is null) return Unauthorized(); bool isValid = _dirSearchService.ValidateCredentials(dirEntryUsername, searchRootCreateDto.Password); if (!isValid) return Unauthorized(Result.Fail().Message(_localizer[Key.UserNotFound])); var userResult = await _userService.ReadByUsernameAsync(dirEntryUsername); if (!userResult.IsSuccess || userResult.Data is null) return Unauthorized(Result.Fail().Message(_localizer[Key.UserNotFoundInLocalDB])); _dirSearchService.SetSearchRootCache(userResult.Data.Username, searchRootCreateDto.Password); return Ok(); } catch (Exception ex) { _logger.LogError(ex, "{Message}", ex.Message); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("SearchByFilter/{filter}")] public IActionResult SearchByFilter([FromRoute] string filter, string? dirEntryUsername, params string[] propName) { try { dirEntryUsername ??= CurrentUser; if (dirEntryUsername is null) return Unauthorized(); return _dirSearchService.FindAllByUserCache(dirEntryUsername, filter, properties: propName).Then(Ok, IActionResult (m, n) => { _logger.LogNotice(n); return StatusCode(StatusCodes.Status424FailedDependency); }); } catch (Exception ex) { _logger.LogError(ex, "{Message}", ex.Message); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("SearchByFilterName/{filterName}")] public IActionResult SearchByFilterName([FromRoute] string filterName, string? dirEntryUsername, params string[] propName) { try { 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."); return _dirSearchService.FindAllByUserCache(dirEntryUsername, filter, properties: propName).Then(Ok, IActionResult (m, n) => { _logger.LogNotice(n); return StatusCode(StatusCodes.Status424FailedDependency); }); } catch (Exception ex) { _logger.LogError(ex, "{Message}", ex.Message); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("Group")] [Authorize] public IActionResult GetGroups(params string[] propName) { try { string 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."); return _dirSearchService.FindAllByUserCache(username: dirEntryUsername, filter, properties: propName).Then(Ok, IActionResult (m, n) => { _logger.LogNotice(n); return StatusCode(StatusCodes.Status424FailedDependency); }); } catch (Exception ex) { _logger.LogError(ex, "{Message}", ex.Message); return StatusCode(StatusCodes.Status500InternalServerError); } } [HttpGet("User")] public IActionResult GetUsersByGroupName([FromQuery] string? groupName = null) { try { string[] propName = { "memberof", "samaccountname", "givenname", "sn", "mail" }; string 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."); return _dirSearchService.FindAllByUserCache(username: dirEntryUsername, filter, properties: propName).Then( Success: data => { if (groupName is not null) data = data .Where(rp => rp.PropertyNames.Cast().Contains("memberof") && rp["memberof"].Cast().Any(ldapDir => ldapDir.Contains(groupName))) .ToList(); return Ok(data); }, Fail: IActionResult (m, n) => { _logger.LogNotice(n); return StatusCode(StatusCodes.Status424FailedDependency); }); } catch (Exception ex) { _logger.LogError(ex, "{Message}", ex.Message); return StatusCode(StatusCodes.Status500InternalServerError); } } private string? CurrentUser { get => (HttpContext.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Name)?.Value); } }