2010-09-30 28 views
10

Tôi có một chuỗi mà tôi đang tìm nạp từ LDAP cho thành viên nhóm Active Directory và tôi cần phân tích cú pháp để kiểm tra xem người dùng có phải là thành viên của nhóm AD hay không. Có một lớp nào có thể phân tích cú pháp này cho tôi không?Có một lớp .NET có thể phân tích CN = chuỗi ra khỏi LDAP không?

Ví dụ:

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

Âm thanh như bạn cần một biểu thức chính quy - RegEx nên thực hiện công việc ... –

+0

Xem http://stackoverflow.com/questions/356480/c-extracting-a-name-from-a-string – nos

+0

Tôi không muốn sử dụng RegEx vì tôi không muốn chịu chi phí kiểm tra. Cảm ơn bạn đã gợi ý. –

Trả lời

4

Bên cạnh đó, nếu bạn truy vấn AD cho một thành viên trong nhóm, bạn sẽ có thể so sánh tất cả distinguishedName của các thành viên của trực tiếp mà không phân tích cú pháp mã thông qua lớp DirectoryEntry của không gian tên System.DirectoryServices.

Nếu không, tôi chỉ không biết một lớp học như vậy ở đâu đó. =)

Hy vọng điều này sẽ giúp bằng cách nào đó!

EDIT # 1

Dưới đây là một liên kết từ mà tôi đã học được rất nhiều làm việc với AD và System.DirectoryServices namespace: Howto: (Almost) Everything In Active Directory via C#

tôi sẽ cung cấp cho bạn với một mã mẫu trong một vài ngày, nếu bạn vẫn yêu cầu nó, nơi tôi sẽ sử dụng lớp đối tượng System.DirectoryServices.DirectorySearcher để truy xuất các thành viên của một nhóm.

Tôi hy vọng liên kết này sẽ giúp bạn như nó đã làm cho tôi! =)

EDIT # 2

Dưới đây là các mẫu mã tôi đã nói với bạn về. Điều này sẽ làm cho nó hiệu quả hơn để truy vấn đối với AD mà không cần phải làm việc bakc và ra khỏi 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; 

} 

Disclaimer: Mã này được cung cấp như-là. Tôi đã thử nghiệm nó trên máy địa phương của tôi và nó hoạt động hoàn toàn tốt đẹp. Nhưng vì tôi phải nhập lại nó ở đây bởi vì tôi không thể chỉ sao chép-dán nó, tôi có lẽ đã phạm một số sai lầm trong khi gõ, điều mà tôi ước không xảy ra.

+0

Điều này đã làm việc khá tốt đối với tôi, vấn đề là chi phí chuyến đi khứ hồi khá đắt đỏ đi qua lại với AD. Đang cố gắng tìm nạp tất cả cùng một lúc. –

+0

Nếu bạn đang sử dụng .NET 3.5 hoặc có thể sử dụng không gian tên 'System.Linq', có thể bạn sẽ quan tâm đến dự án LINQ to AD của Bart De Smet trên Codeplex. Điều này cho phép bạn sử dụng LINQ để truy vấn đối với AD. Thật vậy, có một số việc phải làm để hoàn thành thư viện, nhưng các khía cạnh quan trọng nhất được đề cập trong mã nguồn mở của anh ấy. –

+0

Nếu bạn muốn các thành viên ngay lập tức của một nhóm, hãy gọi 'DirectorySearcher' so với DN của nhóm và nhận thuộc tính' members' của nó cho danh sách DN. Nếu bạn muốn các thành viên lồng nhau của các nhóm trong một nhóm, hãy nhận thuộc tính 'tokenGroups' cho một danh sách các đối tượng SID. Tôi đã viết về điều này một lúc trở lại: http://explodingcoder.com/blog/content/how-query-active-directory-security-group-membership – spoulson

8

Nếu bạn không muốn thêm phụ thuộc bổ sung và chỉ muốn phân tích chuỗi ..

Đây là loại chuỗi có thể dễ dàng được phân tích chỉ sử dụng String.split. Để nhận các giá trị CN, sẽ giống như ..

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 Điều này trả lời câu hỏi và là một giải pháp tốt. –

+21

Đối với những người đọc lại, giải pháp này không đủ cho môi trường sản xuất - [RFC] (http://www.rfc-archive.org/getrfc.php?rfc=4514) chỉ định rằng các giá trị có thể được trích dẫn và cũng có các quy tắc thoát ký tự. Ngoài ra, tách chuỗi bằng dấu phẩy với định dạng này là * rất nguy hiểm. –

6

Đây được gọi là tên phân biệt.

CodeProject có một dự án phân tích cú pháp xuất hiện để làm những gì bạn cần: http://www.codeproject.com/KB/IP/dnparser.aspx

+0

Nó cũng được gói gọn thành một gói github và gói nuget để dễ dàng truy cập. https://github.com/picrap/DNParser/blob/master/README.md –

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

Để trả lời câu hỏi phân tích, sử dụng PInvoke với DsGetRdnW. Đối với mã, xem câu trả lời của tôi cho một câu hỏi khác: https://stackoverflow.com/a/11091804/628981.

Nhưng có vẻ như bạn đang làm sai.Trước tiên, hãy nhận SID cho nhóm mục tiêu của bạn:

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); 

Sau đó, tùy thuộc vào những gì bạn có. Nếu người dùng đang chạy ứng dụng của bạn (hoặc được xác thực cho trang web/dịch vụ của bạn), thì hãy liệt kê các SID trong mã thông báo. Ví dụ: trong ứng dụng dành cho máy tính để bàn, hãy sử dụng WindowsIdentity.GetCurrent().Groups. Nếu không, bạn sẽ cần phải nhận được một DirectoryEntry cho người sử dụng và sau đó nhận được các thuộc tính tokenAttributes như spoulson gợi ý:

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 
    } 
} 

Chỉ trong trường hợp bạn cần phải nhận được một DirectoryEntry từ một SID, bạn có thể nhận được các chuỗi tìm kiếm bằng :

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

Để phân tích cú pháp DistinquishedName bạn phải chú ý đến các ký tự thoát. Đây là một phương thức sẽ phân tích chuỗi chính xác và trả về một danh sách các cặp giá trị khóa.

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

Tuyệt vời - cảm ơn anh chàng! –

+2

Khá giống cách tiếp cận này - mặc dù nó không cắt khoảng trắng từ tên thuộc tính và tôi cũng gặp một số vấn đề với giá trị được trích dẫn, ví dụ: O = "VeriSign, Inc." - vì vậy tôi đã điều chỉnh một chút về https://gist.github.com/davetransom/e9c58b96afa46d4c75a0 –

Các vấn đề liên quan