2010-09-30 76 views
10

我有一個字符串,我從LDAP獲取Active Directory組成員資格,我需要解析它以檢查用戶是否是AD組的成員。有沒有可以爲我解析的類?是否有.NET類可以解析CN =字符串出LDAP?

例子:

CN=Foo Group Name,DC=mydomain,DC=com 
+0

聽起來像是你需要一個正則表達式 - 正則表達式應該做的工作...... – 2010-09-30 18:47:40

+0

見http://stackoverflow.com/questions/356480/c-extracting-a-name-from-a-string – nos 2010-09-30 18:55:19

+0

我不想使用RegEx,因爲我不想承擔測試成本。感謝你的建議。 – 2010-09-30 19:55:53

回答

4

此外,如果你查詢AD的一組成員,你就可以比較所有成員的distinguishedName的直接的,而不解析通過System.DirectoryServices命名空間的DirectoryEntry類代碼。

否則,我只是不知道這樣的類別的地方。 =)

希望這有助於無論如何不知何故!

編輯#1

這裏是我從中學到了很多與AD和System.DirectoryServices命名工作的鏈接:Howto: (Almost) Everything In Active Directory via C#

我將在幾天內爲您提供的樣本代碼,如果您仍然需要它,我將使用System.DirectoryServices.DirectorySearcher對象類來檢索組的成員。

我希望這個鏈接將幫助你,因爲它爲我做! =)

編輯#2

下面的代碼示例中,我告訴你。這應該使它能夠更有效地查詢AD,而不必工作在AD和AD之間。

public IList<string> GetMembers(string groupName) { 
    if (string.IsNullOrEmpty(groupName)) 
     throw new ArgumentNullException("groupName"); 

    IList<string> members = new List<string>(); 

    DirectoryEntry root = new DirectoryEntry(@"LDAP://my.domain.com"); 
    DirectorySearcher searcher = new DirectorySearcher(); 
    searcher.SearchRoot = root; 
    searcher.SearchScope = SearchScope.Subtree; 
    searcher.PropertiesToLoad.Add("member"); 

    searcher.Filter = string.Format("(&(objectClass=group)(sAMAccountName={0}))", groupName); 

    SearchResult result = searcher.FindOne(); 
    DirectoryEntry groupFound = result.GetDirectoryEntry(); 
    for (int index = 0; index < ((object[])groupFound.Properties["member"].Value).Length; ++index) 
     members.Add((string)((object[])groupFound.Properties["member"].Value)[index]); 

    return members; 

} 

聲明提供該代碼原樣。我在我的本地機器上測試過它,它工作得很好。但是由於我不得不在這裏重新輸入它,因爲我不能複製粘貼它,所以我在輸入時可能會犯一些錯誤,而這些錯誤我都沒有發生過。

+0

這對我來說工作得很好,問題在於與AD一起來回的昂貴往返成本。嘗試一種方式一次性獲取它們。 – 2010-09-30 20:24:46

+0

如果您使用的是.NET 3.5或可以使用'System.Linq'命名空間,那麼您可能有興趣關注Codeplex上Bart De Smet的LINQ to AD項目。這允許您使用LINQ來針對AD進行查詢。事實上,完成圖書館還有一些工作要做,但最重要的方面在他的開源代碼中。 – 2010-09-30 20:48:29

+0

如果您想要一個組的直接成員,請針對該組的DN調用「DirectorySearcher」,並獲取其「成員」屬性以獲取DN列表。如果你想要在一個組中嵌套組成員,可以獲得'tokenGroups'屬性來獲取對象SID列表。我寫了一段時間回來:http://explodingcoder.com/blog/content/how-query-active-directory-security-group-membership – spoulson 2010-09-30 22:11:16

8

如果你不想增加額外的依賴關係,只是想解析字符串..

這種類型的字符串可以很容易地只用string.Split進行解析。爲了得到CN值,將會是這樣的......

string[] split = "CN=Foo Group Name,DC=mydomain,DC=com".Split(','); 
List<string> cnValues = new List<string>(); 
foreach(string pair in split){ 
    string[] keyValue=pair.Split('='); 
    if(keyValue[0]=="CN") 
     cnValues.Add(keyValue[1]); 
} 
+0

+1這回答了這個問題,是一個很好的解決方案。 – 2010-10-01 18:48:04

+21

對於那些回讀,這種解決方案對於生產環境是不夠的 - [RFC](http://www.rfc-archive.org/getrfc.php?rfc=4514)指定值可以被引用,還有人物逃脫規則。另外,用這種格式的逗號分割字符串是非常危險的。 – 2011-03-23 18:29:03

6

這些被稱爲辨別名稱。

CodeProject上有出現做你需要什麼解析器項目:http://www.codeproject.com/KB/IP/dnparser.aspx

+0

它也被包裝成github項目和nuget包以方便訪問。 https://github.com/picrap/DNParser/blob/master/README.md – 2018-03-02 20:09:37

2
Using System.DirectoryServices; 

namespace GetGroups 
{ 
    public string GetGroupName(string LDAPGroupEntry) 
    { 
     // LDAPGroupEntry is in the form "LDAP://CN=Foo Group Name,DC=mydomain,DC=com" 
     DirectoryEntry grp = new DirectoryEntry(LDAPGroupEntry); 
     return grp.Properties["Name"].Value.ToString(); 
    } 
} 
0

要回答這個問題的解析,使用的PInvoke與DsGetRdnW。有關代碼,請參閱我對另一個問題的回答:https://stackoverflow.com/a/11091804/628981

但它聽起來像你做錯了。首先,獲取目標羣組的SID:

string targetGroupName = //target group name; 
DirectorySearcher dsTargetGroup = new DirectorySearcher(); 
dsTargetGroup.Filter = string.Format("(sAMAccountName={0})", targetGroupName); 
SearchResult srTargetGroup = dsTargetGroup.FindOne(); 
DirectoryEntry deTargetGroup = srTargetGroup.GetDirectoryEntry(); 
byte[] byteSid = (byte[])deTargetGroup.Properties["objectSid"].Value; 
SecurityIdentifier targetGroupSid = new SecurityIdentifier(byteSid, 0); 

然後,這取決於你有什麼。如果用戶正在運行您的應用程序(或通過身份驗證到您的網站/服務),然後枚舉令牌中的SID。例如,在桌面應用程序中使用WindowsIdentity.GetCurrent().Groups。否則,你就需要獲得一個DirectoryEntry的用戶,然後獲得tokenAttributes屬性像spoulson建議:

DirectoryEntry deTargetUser = //target user; 
DirectorySearcher dsTargetUser = new DirectorySearcher(deTargetUser); 
dsTargetUser.SearchScope = SearchScope.Base; //tokenGroups is a constructed attribute, so have to ask for it while performing a search 
dsTargetUser.Filter = "(objectClass=*)"; //this is closest thing I can find to an always true filter 
dsTargetUser.PropertiesToLoad.Add("tokenGroups"); 
SearchResult srTargetUser = dsTargetUser.FindOne(); 
foreach(byte[] byteGroupSid in srTargetUser.Properties["tokenGroups"]) 
{ 
    SecurityIdentifier groupSid = new SecurityIdentifier(byteGroupSid, 0); 
    if(groupSid == targetGroupSid) 
    { 
     //success 
    } 
} 

萬一你需要從一個SID得到一個DirectoryEntry,你可以得到搜索字符串:

public static string GetSIDSearchFilter(SecurityIdentifier sid) 
{ 
    byte[] byteSid = new byte[sid.BinaryLength]; 
    sid.GetBinaryForm(byteSid, 0); 
    return string.Format("(objectSid={0})", BuildFilterOctetString(byteSid)); 
} 

public static string BuildFilterOctetString(byte[] bytes) 
{ 
    StringBuilder sb = new StringBuilder(); 
    for (int i = 0; i < bytes.Length; i++) 
    { 
     sb.AppendFormat("\\{0}", bytes[i].ToString("X2")); 
    } 
    return sb.ToString(); 
} 
3

要解析DistinquishedName,您必須注意轉義字符。這裏有一個方法可以正確解析字符串並返回一個鍵值對列表。

public static List<KeyValuePair<string, string>> ParseDistinguishedName(string input) 
    { 
     int i = 0; 
     int a = 0; 
     int v = 0; 
     var attribute = new char[50]; 
     var value = new char[200]; 
     var inAttribute = true; 
     string attributeString, valueString; 
     var names = new List<KeyValuePair<string, string>>(); 

     while (i < input.Length) 
     { 
      char ch = input[i++]; 
      switch(ch) 
      { 
       case '\\': 
        value[v++] = ch; 
        value[v++] = input[i++]; 
        break; 
       case '=': 
        inAttribute = false; 
        break; 
       case ',': 
        inAttribute = true; 
        attributeString = new string(attribute).Substring(0, a); 
        valueString = new string(value).Substring(0, v); 
        names.Add(new KeyValuePair<string, string>(attributeString, valueString)); 
        a = v = 0; 
        break; 
       default: 
        if (inAttribute) 
        { 
         attribute[a++] = ch; 
        } 
        else 
        { 
         value[v++] = ch; 
        } 
        break; 
      } 
     } 

     attributeString = new string(attribute).Substring(0, a); 
     valueString = new string(value).Substring(0, v); 
     names.Add(new KeyValuePair<string, string>(attributeString, valueString)); 
     return names; 
    } 

    static void Main(string[] args) 
    { 
     const string TestString = "CN=BY2STRAKRJOB2,OU=MSNStorage,OU=RESOURCE,OU=PRODUCTION,DC=phx,DC=gbl,STREET=street address,L=locality Name,C=Country Name,UID=user id,STUFF=\\,\\.\\+\"<>;\\=\\0A"; 

     var names = ParseDistinguishedName(TestString); 
     foreach (var pair in names) 
     { 
      Console.WriteLine("{0} = {1}", pair.Key, pair.Value); 
     } 
    } 
+0

真棒 - 感謝老兄! – 2015-01-26 01:58:19

+2

非常喜歡這種方法 - 儘管它不修剪屬性名稱中的空白,並且我也有一些引用值的問題,例如O =「VeriSign,Inc.」 - 所以我稍微調整了一些東西https://gist.github.com/davetransom/e9c58b96afa46d4c75a0 – 2015-04-10 23:55:00