Pin Active Directory provider to domain controller

This commit is contained in:
Meik
2026-05-19 20:01:52 +02:00
parent 723eae1018
commit a9b4cfe10b
5 changed files with 135 additions and 12 deletions

View File

@@ -3,6 +3,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using System.DirectoryServices.AccountManagement;
using System.IO;
using System.Linq;
@@ -25,6 +26,7 @@ namespace LiamAD
private cADLogonInfo privLogonInfo = null;
public PrincipalContext adContext = null;
public DirectoryEntry directoryEntry = null;
public string EffectiveDomainController { get; private set; } = null;
public Exception LastException { get; private set; } = null;
public string LastErrorMessage { get; private set; } = null;
@@ -50,8 +52,12 @@ namespace LiamAD
//TODO: remove dummy delay?
await Task.Delay(0);
ResetError();
adContext = new PrincipalContext(ContextType.Domain, LogonInfo.Domain, LogonInfo.User, new NetworkCredential("", LogonInfo.UserSecret).Password);
var ldapPath = $"LDAP://{LogonInfo.Domain}/{LogonInfo.TargetGroupPath}";
var adServer = ResolveEffectiveDomainController(LogonInfo);
adContext = new PrincipalContext(ContextType.Domain, adServer, LogonInfo.User, new NetworkCredential("", LogonInfo.UserSecret).Password);
EffectiveDomainController = adContext.ConnectedServer ?? adServer;
LogEntry($"AD provider domain controller pinned to '{EffectiveDomainController}' for domain '{LogonInfo.Domain}'.", LogLevels.Debug);
var ldapPath = $"LDAP://{EffectiveDomainController}/{LogonInfo.TargetGroupPath}";
directoryEntry = new DirectoryEntry
{
Path = ldapPath,
@@ -70,6 +76,78 @@ namespace LiamAD
return false;
}
private string ResolveEffectiveDomainController(cADLogonInfo logonInfo)
{
var configuredDomainControllers = ParseDomainControllers(logonInfo?.DomainControllers);
foreach (var domainController in configuredDomainControllers)
{
if (CanConnectToDomainController(domainController, logonInfo))
return domainController;
LogEntry($"Configured AD provider domain controller '{domainController}' is not reachable. Trying next candidate.", LogLevels.Warning);
}
var pdc = TryGetPdcRoleOwner(logonInfo);
if (!string.IsNullOrWhiteSpace(pdc))
return pdc;
LogEntry($"Could not determine PDC emulator for domain '{logonInfo?.Domain}'. Falling back to domain locator.", LogLevels.Warning);
return logonInfo?.Domain;
}
private static IEnumerable<string> ParseDomainControllers(string domainControllers)
{
if (string.IsNullOrWhiteSpace(domainControllers))
return Enumerable.Empty<string>();
return domainControllers
.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
.Select(i => i.Trim())
.Where(i => !string.IsNullOrWhiteSpace(i));
}
private bool CanConnectToDomainController(string domainController, cADLogonInfo logonInfo)
{
try
{
using (var context = new PrincipalContext(ContextType.Domain, domainController, logonInfo.User, new NetworkCredential("", logonInfo.UserSecret).Password))
return !string.IsNullOrWhiteSpace(context.ConnectedServer);
}
catch (Exception E)
{
LogException(E, LogLevels.Debug);
return false;
}
}
private string TryGetPdcRoleOwner(cADLogonInfo logonInfo)
{
try
{
var credentials = new DirectoryContext(
DirectoryContextType.Domain,
logonInfo.Domain,
logonInfo.User,
new NetworkCredential("", logonInfo.UserSecret).Password);
using (var domain = Domain.GetDomain(credentials))
return domain?.PdcRoleOwner?.Name;
}
catch (Exception E)
{
LogException(E, LogLevels.Debug);
return null;
}
}
private string GetAdServer()
{
if (!string.IsNullOrWhiteSpace(EffectiveDomainController))
return EffectiveDomainController;
return privLogonInfo?.Domain;
}
private async Task<bool> privRelogon()
{
if (privLogonInfo == null)
@@ -193,7 +271,7 @@ namespace LiamAD
string managedByDn = k.Properties["managedBy"][0].ToString();
// Erstellen eines DirectoryEntry-Objekts für den managedBy-DN
using (DirectoryEntry managedByEntry = new DirectoryEntry($"LDAP://{managedByDn}"))
using (DirectoryEntry managedByEntry = new DirectoryEntry($"LDAP://{GetAdServer()}/{managedByDn}", privLogonInfo.User, new NetworkCredential("", privLogonInfo.UserSecret).Password, AuthenticationTypes.Secure | AuthenticationTypes.Sealing))
{
if (managedByEntry.Properties.Contains("objectSid") && managedByEntry.Properties["objectSid"].Count > 0)
{
@@ -513,4 +591,4 @@ namespace LiamAD
return null;
}
}
}
}