.NET LDAP路径实用程序(C#)

是否有用于LDAP路径操作的.NET库?
我想有一些等同于System.IO.Path东西,允许例如做类似的东西

 string ou1 = LDAPPath.Combine("OU=users","DC=x,DC=y"); string ou2 = LDAPPath.Parent("CN=someone,OU=users,DC=x,DC=y"); 

否则,在.NET中处理LDAP专有名称的常用方法是什么?

澄清我的问题 :我一般不会问“.NET中的目录服务”; 我已经使用过它并完成了一些程序来执行某些任务。 我觉得缺少的是一种操纵路径 ,解析专有名称等的正确方法,因为这应该是一个非常常见的需求,我希望有一种更简洁的方法来做到这一点,而不是在逗号上分割字符串(1)。

(1)例如,像在库中调用一个函数来分割逗号上的字符串

不,不是我的知识 – 甚至不是最新的.NET 3.5命名空间用于Active Directory。

您可以在目录本身中导航层次结构(转到父级等) – 但您需要通过DirectoryEntry绑定到例如Active DirectoryEntry

然后是NameTranslate API ,但这更像是“将此名称更改为其他名称”,例如从用户主体名称更改为相对DN – 再次,它需要连接到AD中的DirectoryEntry

我最感兴趣的是找到这样一个库,但到目前为止,我还没有听说过 – 无论是.NET还是其他任何语言。

回到我的“重型”AD编程时代,我有自己的一套LDAP路径操作例程(在Delphi中) – 基本上只是字符串解析和处理。

我使用了几个基于Win32方法DsGetRdnW,DsQuoteRdnValueW和DsUnquoteRdnValueW的实用程序类:

 using System; using System.ComponentModel; using System.Collections.Generic; using System.Runtime.InteropServices; namespace UnmanagedCode { public class PInvoke { #region Constants public const int ERROR_SUCCESS = 0; public const int ERROR_BUFFER_OVERFLOW = 111; #endregion Constants #region DN Parsing [DllImport("ntdsapi.dll", CharSet = CharSet.Unicode)] protected static extern int DsGetRdnW( ref IntPtr ppDN, ref int pcDN, out IntPtr ppKey, out int pcKey, out IntPtr ppVal, out int pcVal ); public static KeyValuePair GetName(string distinguishedName) { IntPtr pDistinguishedName = Marshal.StringToHGlobalUni(distinguishedName); try { IntPtr pDN = pDistinguishedName, pKey, pVal; int cDN = distinguishedName.Length, cKey, cVal; int lastError = DsGetRdnW(ref pDN, ref cDN, out pKey, out cKey, out pVal, out cVal); if(lastError == ERROR_SUCCESS) { string key, value; if(cKey < 1) { key = string.Empty; } else { key = Marshal.PtrToStringUni(pKey, cKey); } if(cVal < 1) { value = string.Empty; } else { value = Marshal.PtrToStringUni(pVal, cVal); } return new KeyValuePair(key, value); } else { throw new Win32Exception(lastError); } } finally { Marshal.FreeHGlobal(pDistinguishedName); } } public static IEnumerable> ParseDN(string distinguishedName) { List components = new List>(); IntPtr pDistinguishedName = Marshal.StringToHGlobalUni(distinguishedName); try { IntPtr pDN = pDistinguishedName, pKey, pVal; int cDN = distinguishedName.Length, cKey, cVal; do { int lastError = DsGetRdnW(ref pDN, ref cDN, out pKey, out cKey, out pVal, out cVal); if(lastError = ERROR_SUCCESS) { string key, value; if(cKey < 0) { key = null; } else if(cKey == 0) { key = string.Empty; } else { key = Marshal.PtrToStringUni(pKey, cKey); } if(cVal < 0) { value = null; } else if(cVal == 0) { value = string.Empty; } else { value = Marshal.PtrToStringUni(pVal, cVal); } components.Add(new KeyValuePair(key, value)); pDN = (IntPtr)(pDN.ToInt64() + UnicodeEncoding.CharSize); //skip over comma cDN--; } else { throw new Win32Exception(lastError); } } while(cDN > 0); return components; } finally { Marshal.FreeHGlobal(pDistinguishedName); } } [DllImport("ntdsapi.dll", CharSet = CharSet.Unicode)] protected static extern int DsQuoteRdnValueW( int cUnquotedRdnValueLength, string psUnquotedRdnValue, ref int pcQuotedRdnValueLength, IntPtr psQuotedRdnValue ); public static string QuoteRDN(string rdn) { if (rdn == null) return null; int initialLength = rdn.Length; int quotedLength = 0; IntPtr pQuotedRDN = IntPtr.Zero; int lastError = DsQuoteRdnValueW(initialLength, rdn, ref quotedLength, pQuotedRDN); switch (lastError) { case ERROR_SUCCESS: { return string.Empty; } case ERROR_BUFFER_OVERFLOW: { break; //continue } default: { throw new Win32Exception(lastError); } } pQuotedRDN = Marshal.AllocHGlobal(quotedLength * UnicodeEncoding.CharSize); try { lastError = DsQuoteRdnValueW(initialLength, rdn, ref quotedLength, pQuotedRDN); switch(lastError) { case ERROR_SUCCESS: { return Marshal.PtrToStringUni(pQuotedRDN, quotedLength); } default: { throw new Win32Exception(lastError); } } } finally { if(pQuotedRDN != IntPtr.Zero) { Marshal.FreeHGlobal(pQuotedRDN); } } } [DllImport("ntdsapi.dll", CharSet = CharSet.Unicode)] protected static extern int DsUnquoteRdnValueW( int cQuotedRdnValueLength, string psQuotedRdnValue, ref int pcUnquotedRdnValueLength, IntPtr psUnquotedRdnValue ); public static string UnquoteRDN(string rdn) { if (rdn == null) return null; int initialLength = rdn.Length; int unquotedLength = 0; IntPtr pUnquotedRDN = IntPtr.Zero; int lastError = DsUnquoteRdnValueW(initialLength, rdn, ref unquotedLength, pUnquotedRDN); switch (lastError) { case ERROR_SUCCESS: { return string.Empty; } case ERROR_BUFFER_OVERFLOW: { break; //continue } default: { throw new Win32Exception(lastError); } } pUnquotedRDN = Marshal.AllocHGlobal(unquotedLength * UnicodeEncoding.CharSize); try { lastError = DsUnquoteRdnValueW(initialLength, rdn, ref unquotedLength, pUnquotedRDN); switch(lastError) { case ERROR_SUCCESS: { return Marshal.PtrToStringUni(pUnquotedRDN, unquotedLength); } default: { throw new Win32Exception(lastError); } } } finally { if(pUnquotedRDN != IntPtr.Zero) { Marshal.FreeHGlobal(pUnquotedRDN); } } } #endregion DN Parsing } public class DNComponent { public string Type { get; protected set; } public string EscapedValue { get; protected set; } public string UnescapedValue { get; protected set; } public string WholeComponent { get; protected set; } public DNComponent(string component, bool isEscaped) { string[] tokens = component.Split(new char[] { '=' }, 2); setup(tokens[0], tokens[1], isEscaped); } public DNComponent(string key, string value, bool isEscaped) { setup(key, value, isEscaped); } private void setup(string key, string value, bool isEscaped) { Type = key; if(isEscaped) { EscapedValue = value; UnescapedValue = PInvoke.UnquoteRDN(value); } else { EscapedValue = PInvoke.QuoteRDN(value); UnescapedValue = value; } WholeComponent = Type + "=" + EscapedValue; } public override bool Equals(object obj) { if (obj is DNComponent) { DNComponent dnObj = (DNComponent)obj; return dnObj.WholeComponent.Equals(this.WholeComponent, StringComparison.CurrentCultureIgnoreCase); } return base.Equals(obj); } public override int GetHashCode() { return WholeComponent.GetHashCode(); } } public class DistinguishedName { public DNComponent[] Components { get { return components.ToArray(); } } private List components; private string cachedDN; public DistinguishedName(string distinguishedName) { cachedDN = distinguishedName; components = new List(); foreach (KeyValuePair kvp in PInvoke.ParseDN(distinguishedName)) { components.Add(new DNComponent(kvp.Key, kvp.Value, true)); } } public DistinguishedName(IEnumerable dnComponents) { components = new List(dnComponents); cachedDN = GetWholePath(","); } public bool Contains(DNComponent dnComponent) { return components.Contains(component); } public string GetDNSDomainName() { List dcs = new List(); foreach (DNComponent dnc in components) { if(dnc.Type.Equals("DC", StringComparison.CurrentCultureIgnoreCase)) { dcs.Add(dnc.UnescapedValue); } } return string.Join(".", dcs.ToArray()); } public string GetDomainDN() { List dcs = new List(); foreach (DNComponent dnc in components) { if(dnc.Type.Equals("DC", StringComparison.CurrentCultureIgnoreCase)) { dcs.Add(dnc.WholeComponent); } } return string.Join(",", dcs.ToArray()); } public string GetWholePath() { return GetWholePath(","); } public string GetWholePath(string separator) { List parts = new List(); foreach (DNComponent component in components) { parts.Add(component.WholeComponent); } return string.Join(separator, parts.ToArray()); } public DistinguishedName GetParent() { if(components.Count == 1) { return null; } List tempList = new List(components); tempList.RemoveAt(0); return new DistinguishedName(tempList); } public override bool Equals(object obj) { if(obj is DistinguishedName) { DistinguishedName objDN = (DistinguishedName)obj; if (this.Components.Length == objDN.Components.Length) { for (int i = 0; i < this.Components.Length; i++) { if (!this.Components[i].Equals(objDN.Components[i])) { return false; } } return true; } return false; } return base.Equals(obj); } public override int GetHashCode() { return cachedDN.GetHashCode(); } } } 

虽然.NET中没有LDAP路径解析器,但是有一个URI解析器。 对于那些只需要解析“LDAP:// domain / …”路径的人,你可以使用System.Uri类,然后你可以获得如下的一些细节:

 var uri = new Uri(SomeDomainURI); var scheme = uri.Scheme; // == "LDAP" or "LDAPS" usually var domainHost = uri.Host; var path = uri.AbsolutePath.TrimStart('/'); 

如果您使用此DN解析器,您还可以执行以下操作来解析路径:

 var dn = new DN(uri.AbsolutePath.TrimStart('/')); 

虽然我同意.NET现在已经有了这个(羞耻!),但这至少可以解决我的需求,虽然并不完美,但我怀疑它对每个人来说都足够强大。