From 67049f229ddee0bb170d077cfa0578c80f86f0db Mon Sep 17 00:00:00 2001 From: Ales Jeusnik Date: Thu, 24 Nov 2022 15:13:56 +0100 Subject: [PATCH 1/2] Get RootDse entry with all attributes in a single request, add cancellation tokens to async search extensions. --- LdapForNet/LdapSearchExtensions.cs | 63 +++++++++++++++--------------- 1 file changed, 32 insertions(+), 31 deletions(-) diff --git a/LdapForNet/LdapSearchExtensions.cs b/LdapForNet/LdapSearchExtensions.cs index 94e9b63..74e0323 100644 --- a/LdapForNet/LdapSearchExtensions.cs +++ b/LdapForNet/LdapSearchExtensions.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using System.Threading; using System.Threading.Tasks; using LdapForNet.Utils; using static LdapForNet.Native.Native; @@ -8,40 +9,38 @@ namespace LdapForNet { public static class LdapSearchExtensions { - public static IList SearchByCn(this ILdapConnection connection, string @base, string cn, - LdapSearchScope scope = LdapSearchScope.LDAP_SCOPE_SUBTREE) + public static LdapEntry GetRootDse(this ILdapConnection connection) { - return connection.Search(@base, $"(cn={cn})", scope: scope); + return connection.Search( + null, + "(objectclass=*)", + new[] { "*", "+", "supportedExtension" }, + LdapSearchScope.LDAP_SCOPE_BASE) + .First(); } - public static LdapEntry GetRootDse(this ILdapConnection connection) + public static async Task GetRootDseAsync(this ILdapConnection connection, + CancellationToken token = default) { - var result = connection.Search(null, "(objectclass=*)", - new[] - { - "namingContexts", "subschemaSubentry", "supportedLDAPVersion", "supportedSASLMechanisms", - "supportedExtension", "supportedControl", "supportedFeatures", "vendorName", "vendorVersion" - }, LdapSearchScope.LDAP_SCOPE_BASE) - .FirstOrDefault(); - if (result == null) - { - return null; - } - - var rootDse = connection.Search(null, "(objectclass=*)", scope: LdapSearchScope.LDAP_SCOPE_BASE).First(); - foreach (var attribute in rootDse.DirectoryAttributes) - { - result.DirectoryAttributes.Remove(attribute.Name); - result.DirectoryAttributes.Add(attribute); - } + return (await connection.SearchAsync( + null, + "(objectclass=*)", + new[] { "*", "+", "supportedExtension" }, + LdapSearchScope.LDAP_SCOPE_BASE, + token)) + .First(); + } - return result; + public static IList SearchByCn(this ILdapConnection connection, string @base, string cn, + LdapSearchScope scope = LdapSearchScope.LDAP_SCOPE_SUBTREE) + { + return connection.Search(@base, $"(cn={cn})", scope: scope); } public static async Task> SearchByCnAsync(this ILdapConnection connection, string @base, - string cn, LdapSearchScope scope = LdapSearchScope.LDAP_SCOPE_SUBTREE) + string cn, LdapSearchScope scope = LdapSearchScope.LDAP_SCOPE_SUBTREE, CancellationToken token = default) { - return await connection.SearchAsync(@base, $"(cn={cn})", scope: scope); + return await connection.SearchAsync(@base, $"(cn={cn})", scope: scope, token: token); } public static IList SearchByCn(this ILdapConnection connection, string cn) @@ -49,9 +48,10 @@ public static IList SearchByCn(this ILdapConnection connection, strin return connection.SearchByCn(LdapUtils.GetDnFromHostname(), cn); } - public static async Task> SearchByCnAsync(this ILdapConnection connection, string cn) + public static async Task> SearchByCnAsync(this ILdapConnection connection, string cn, + CancellationToken token = default) { - return await connection.SearchByCnAsync(LdapUtils.GetDnFromHostname(), cn); + return await connection.SearchByCnAsync(LdapUtils.GetDnFromHostname(), cn, token: token); } public static IList SearchBySid(this ILdapConnection connection, string @base, string sid, @@ -62,10 +62,10 @@ public static IList SearchBySid(this ILdapConnection connection, stri } public static async Task> SearchBySidAsync(this ILdapConnection connection, string @base, - string sid, LdapSearchScope scope = LdapSearchScope.LDAP_SCOPE_SUBTREE) + string sid, LdapSearchScope scope = LdapSearchScope.LDAP_SCOPE_SUBTREE, CancellationToken token = default) { var hex = HexEscaper.Escape(LdapSidConverter.ConvertToHex(sid)); - return await connection.SearchAsync(@base, $"(objectSID={hex})", scope: scope); + return await connection.SearchAsync(@base, $"(objectSID={hex})", scope: scope, token: token); } public static IList SearchBySid(this ILdapConnection connection, string sid) @@ -73,9 +73,10 @@ public static IList SearchBySid(this ILdapConnection connection, stri return connection.SearchBySid(LdapUtils.GetDnFromHostname(), sid); } - public static async Task> SearchBySidAsync(this ILdapConnection connection, string sid) + public static async Task> SearchBySidAsync(this ILdapConnection connection, string sid, + CancellationToken token = default) { - return await connection.SearchBySidAsync(LdapUtils.GetDnFromHostname(), sid); + return await connection.SearchBySidAsync(LdapUtils.GetDnFromHostname(), sid, token: token); } } } \ No newline at end of file From 5b074289d996fc9a283974318258b517eac51ffa Mon Sep 17 00:00:00 2001 From: Ales Jeusnik Date: Thu, 1 Dec 2022 13:53:22 +0100 Subject: [PATCH 2/2] RootDse search extensions should now work for all servers, added some common attributes for popular vendors. --- LdapForNet/LdapSearchExtensions.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/LdapForNet/LdapSearchExtensions.cs b/LdapForNet/LdapSearchExtensions.cs index 74e0323..f789e59 100644 --- a/LdapForNet/LdapSearchExtensions.cs +++ b/LdapForNet/LdapSearchExtensions.cs @@ -14,7 +14,14 @@ public static LdapEntry GetRootDse(this ILdapConnection connection) return connection.Search( null, "(objectclass=*)", - new[] { "*", "+", "supportedExtension" }, + new[] + { + "*", "+", "serverName", "dNSHostName", "dsServiceName", "currentTime", "defaultNamingContext", + "rootDomainNamingContext", "configurationNamingContext", "schemaNamingContext", "subschemaSubentry", + "namingContexts", "supportedLDAPVersion", "supportedCapabilities", "supportedControl", + "supportedLDAPPolicies", "supportedSaslMechanisms", "supportedExtension", "vendorName", "vendorVersion", + "domainControllerFunctionality", "domainFunctionality", "forestFunctionality", "isSynchronized", "objectClass" + }, LdapSearchScope.LDAP_SCOPE_BASE) .First(); } @@ -25,7 +32,14 @@ public static async Task GetRootDseAsync(this ILdapConnection connect return (await connection.SearchAsync( null, "(objectclass=*)", - new[] { "*", "+", "supportedExtension" }, + new[] + { + "*", "+", "serverName", "dNSHostName", "dsServiceName", "currentTime", "defaultNamingContext", + "rootDomainNamingContext", "configurationNamingContext", "schemaNamingContext", "subschemaSubentry", + "namingContexts", "supportedLDAPVersion", "supportedCapabilities", "supportedControl", + "supportedLDAPPolicies", "supportedSaslMechanisms", "supportedExtension", "vendorName", "vendorVersion", + "domainControllerFunctionality", "domainFunctionality", "forestFunctionality", "isSynchronized", "objectClass" + }, LdapSearchScope.LDAP_SCOPE_BASE, token)) .First();