diff --git a/src/CommonLib/LdapUtils.cs b/src/CommonLib/LdapUtils.cs index 14612da12..f76782b8e 100644 --- a/src/CommonLib/LdapUtils.cs +++ b/src/CommonLib/LdapUtils.cs @@ -143,6 +143,9 @@ public IAsyncEnumerable> PagedQuery(LdapQueryParame if (Cache.GetIDType(sid, out var type)) { return (true, type); } + else if (_unresolvablePrincipals.Contains(GetDomainSidFromObjectSid(sid))) { + return (false, Label.Base); + } var tempDomain = domain; @@ -330,14 +333,7 @@ public IAsyncEnumerable> PagedQuery(LdapQueryParame } public virtual async Task<(bool Success, string DomainName)> GetDomainNameFromSid(string sid) { - string domainSid; - try { - domainSid = new SecurityIdentifier(sid).AccountDomainSid?.Value.ToUpper(); - } - catch { - var match = SIDRegex.Match(sid); - domainSid = match.Success ? match.Groups[1].Value : null; - } + var domainSid = GetDomainSidFromObjectSid(sid); if (domainSid == null) { return (false, ""); @@ -384,8 +380,26 @@ public IAsyncEnumerable> PagedQuery(LdapQueryParame return (false, string.Empty); } + private string GetDomainSidFromObjectSid(string sid) { + try { + return new SecurityIdentifier(sid).AccountDomainSid?.Value.ToUpper(); + } + catch { + var match = SIDRegex.Match(sid); + return match.Success ? match.Groups[1].Value : null; + } + } + private async Task<(bool Success, string DomainName)> ConvertDomainSidToDomainNameFromLdap(string domainSid) { - if (!GetDomain(out var domain) || domain?.Name == null) { + Domain domain; + try { + if (!GetDomainWithUnreachableThrow(out domain) || domain?.Name == null) { + return (false, string.Empty); + } + } + catch (ActiveDirectoryOperationException) { + // Domain is unreachable, add to unresolvable sids + _unresolvablePrincipals.Add(domainSid); return (false, string.Empty); } @@ -576,6 +590,31 @@ public bool GetDomain(out Domain domain) { } } + private bool GetDomainWithUnreachableThrow(out Domain domain) { + if (_domainCache.TryGetValue(_nullCacheKey, out domain)) return true; + + try { + var context = _ldapConfig.Username != null + ? new DirectoryContext(DirectoryContextType.Domain, _ldapConfig.Username, + _ldapConfig.Password) + : new DirectoryContext(DirectoryContextType.Domain); + + // Blocking External Call + domain = Domain.GetDomain(context); + _domainCache.TryAdd(_nullCacheKey, domain); + return true; + } + catch (ActiveDirectoryOperationException e) when (e.Message.Equals("Current security context is not associated with an Active Directory domain or forest.", StringComparison.OrdinalIgnoreCase)) { + // This domain is unreachable + throw; + } + catch (Exception e) { + _log.LogDebug(e, "GetDomain call failed for blank domain"); + domain = null; + return false; + } + } + public async Task<(bool Success, TypedPrincipal Principal)> ResolveAccountName(string name, string domain) { if (string.IsNullOrWhiteSpace(name)) { return (false, null);