代码之家  ›  专栏  ›  技术社区  ›  Paolo Tedesco

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

  •  3
  • Paolo Tedesco  · 技术社区  · 16 年前

    是否有用于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) 例如,在库中调用函数以逗号分隔字符串

    3 回复  |  直到 16 年前
        1
  •  5
  •   Sean Hall    13 年前

    我使用了两个基于Win32方法DSGetrDw、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<string, string> 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<string, string>(key, value);
                    }
                    else
                    {
                        throw new Win32Exception(lastError);
                    }
                }
                finally
                {
                    Marshal.FreeHGlobal(pDistinguishedName);
                }
            }
    
            public static IEnumerable<KeyValuePair<string, string>> ParseDN(string distinguishedName)
            {
                List<KeyValuePair<string, string> components = new List<KeyValuePair<string, string>>();
                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<string, string>(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<DNComponent> components;
            private string cachedDN;
    
            public DistinguishedName(string distinguishedName)
            {
                cachedDN = distinguishedName;
                components = new List<DNComponent>();
                foreach (KeyValuePair<string, string> kvp in PInvoke.ParseDN(distinguishedName))
                {
                    components.Add(new DNComponent(kvp.Key, kvp.Value, true));
                }
            }
    
            public DistinguishedName(IEnumerable<DNComponent> dnComponents)
            {
                components = new List<DNComponent>(dnComponents);
                cachedDN = GetWholePath(",");
            }
    
            public bool Contains(DNComponent dnComponent)
            {
                return components.Contains(component);
            }
    
            public string GetDNSDomainName()
            {
                List<string> dcs = new List<string>();
                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<string> dcs = new List<string>();
                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<string> parts = new List<string>();
                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<DNComponent> tempList = new List<DNComponent>(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();
            }
        }
    }
    
        2
  •  2
  •   marc_s MisterSmith    16 年前

    不,据我所知,甚至在Active Directory的最新.NET 3.5命名空间中也没有。

    您可以在目录本身中导航层次结构(转到父目录等),但您需要通过 DirectoryEntry

    然后是 NameTranslate API ,但这实际上更多的是“将此名称更改为另一个名称”,例如,从用户主体名称更改为相对DN,并且再次需要连接到 在广告中。

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

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

    马克

        3
  •  0
  •   James Wilkins    10 年前

    虽然.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('/');
    

    如果你使用 this DN parser 您也可以执行以下操作来解析路径:

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