2011-06-06 15 views
31

मैं के माध्यम से नेस्ट समूहों है कि एक उपयोगकर्ता सक्रिय निर्देशिका में का एक सदस्य है, दोनों स्पष्ट रूप से memberOf संपत्ति सूची में सूचीबद्ध के सभी की एक सूची प्राप्त करने के साथ ही परोक्ष करने के लिए देख रहा हूँ समूह की सदस्यता। उदाहरण के लिए, यदि मैं यूजरए और यूजरए की जांच करता हूं तो ग्रुप ए और ग्रुपबी का हिस्सा है, तो ग्रुपबी ग्रुप सी का सदस्य होने पर भी मैं ग्रुपसी को सूचीबद्ध करना चाहता हूं।रिकर्सिव समूह सदस्यता (सक्रिय निर्देशिका) का पता लगाएं, का उपयोग करते हुए सी #

आप अपने आवेदन में थोड़ा अधिक जानकारी देने के लिए, मैं एक सीमित आधार पर यह कर दिया जाएगा। असल में, मैं कभी-कभी सुरक्षा जांच चाहता हूं जो इन अतिरिक्त सदस्यताों की सूची देगा। मैं दोनों को अलग करना चाहता हूं लेकिन यह मुश्किल नहीं होना चाहिए।

मेरे समस्या यह है कि मैं एक कारगर तरीका इस क्वेरी काम करने के लिए नहीं मिला है है। सक्रिय निर्देशिका (This CodeProject Article) पर मानक पाठ ऐसा करने का एक तरीका दिखाता है जो मूल रूप से एक पुनरावर्ती लुकअप है। यह बहुत अक्षम है। यहां तक ​​कि मेरे छोटे डोमेन में, उपयोगकर्ता के पास 30+ समूह सदस्यता हो सकती है। इसका मतलब है कि एक उपयोगकर्ता के लिए सक्रिय निर्देशिका में 30+ कॉल।

मैं निम्नलिखित LDAP कोड देखा है एक बार में memberOf प्रविष्टियों के सभी प्राप्त करने के लिए:

(memberOf:1.2.840.113556.1.4.1941:={0}) 

जहां {0} मेरी LDAP पथ होगा (पूर्व: सीएन = UserA, OU = उपयोगकर्ता, डीसी = foo, डीसी = ऑर्ग)। हालांकि, यह किसी भी रिकॉर्ड वापस नहीं करता है। इस विधि के नकारात्मक पक्ष, भले ही यह काम करता है, यह होगा कि मैं नहीं जानता कि कौन सा समूह स्पष्ट था और जो अंतर्निहित था।

है यही कारण है कि मैं अब तक की है। मैं जानना चाहता हूं कि कोडप्रोजेक्ट आलेख से बेहतर तरीका है या नहीं, और यदि ऐसा है, तो यह कैसे पूरा किया जा सकता है (वास्तविक कोड अद्भुत होगा)। मैं .NET 4.0 और C# का उपयोग कर रहा हूं। मेरी सक्रिय निर्देशिका विंडोज 2008 कार्यात्मक स्तर पर है (यह अभी तक आर 2 नहीं है)।

उत्तर

22

यह एक दिलचस्प सवाल के लिए प्यास धन्यवाद।

इसके बाद, बस एक सुधार, आप कहते हैं:

मैं निम्नलिखित LDAP कोड देखा है एक बार में memberOf प्रविष्टियों के सभी प्राप्त करने के लिए:

(memberOf:1.2.840.113556.1.4.1941:={0}) 

आप यह काम नहीं करते । मुझे याद है कि जब मैं अपने अस्तित्व के बारे में सीखा, तो मैं इसे काम करता हूं, लेकिन यह एक LDIFDE.EXE फ़िल्टर में था। तो मैं इसे सी # में एडीएसआई पर लागू करता हूं और यह अभी भी काम कर रहा है। माइक्रोसॉफ्ट से लिया गया नमूना में बहुत अधिक कंस्ट्रैसिस था, लेकिन यह काम कर रहा था (source in AD Search Filter Syntax)।

इस तथ्य से संबंधित आपकी टिप्पणी के अनुसार कि हम नहीं जानते कि कोई उपयोगकर्ता स्पष्ट रूप से समूह से संबंधित है या नहीं, मैं एक और अनुरोध जोड़ता हूं। मुझे पता है कि यह बहुत अच्छा नहीं है, लेकिन यह सबसे अच्छा है कि मैं करने योग्य हूं।

static void Main(string[] args) 
{ 
    /* Connection to Active Directory 
    */ 
    DirectoryEntry deBase = new DirectoryEntry("LDAP://WM2008R2ENT:389/dc=dom,dc=fr"); 


    /* To find all the groups that "user1" is a member of : 
    * Set the base to the groups container DN; for example root DN (dc=dom,dc=fr) 
    * Set the scope to subtree 
    * Use the following filter : 
    * (member:1.2.840.113556.1.4.1941:=cn=user1,cn=users,DC=x) 
    */ 
    DirectorySearcher dsLookFor = new DirectorySearcher(deBase); 
    dsLookFor.Filter = "(member:1.2.840.113556.1.4.1941:=CN=user1 Users,OU=MonOu,DC=dom,DC=fr)"; 
    dsLookFor.SearchScope = SearchScope.Subtree; 
    dsLookFor.PropertiesToLoad.Add("cn"); 

    SearchResultCollection srcGroups = dsLookFor.FindAll(); 

    /* Just to know if user is explicitly in group 
    */ 
    foreach (SearchResult srcGroup in srcGroups) 
    { 
    Console.WriteLine("{0}", srcGroup.Path); 

    foreach (string property in srcGroup.Properties.PropertyNames) 
    { 
     Console.WriteLine("\t{0} : {1} ", property, srcGroup.Properties[property][0]); 
    } 

    DirectoryEntry aGroup = new DirectoryEntry(srcGroup.Path); 
    DirectorySearcher dsLookForAMermber = new DirectorySearcher(aGroup); 
    dsLookForAMermber.Filter = "(member=CN=user1 Users,OU=MonOu,DC=dom,DC=fr)"; 
    dsLookForAMermber.SearchScope = SearchScope.Base; 
    dsLookForAMermber.PropertiesToLoad.Add("cn"); 

    SearchResultCollection memberInGroup = dsLookForAMermber.FindAll(); 
    Console.WriteLine("Find the user {0}", memberInGroup.Count); 

    } 

    Console.ReadLine(); 
} 

अपने परीक्षण ट्री में इस दे:

LDAP://WM2008R2ENT:389/CN=MonGrpSec,OU=MonOu,DC=dom,DC=fr 
adspath : LDAP://WM2008R2ENT:389/CN=MonGrpSec,OU=MonOu,DC=dom,DC=fr 
cn : MonGrpSec 
Find the user 1 

LDAP://WM2008R2ENT:389/CN=MonGrpDis,OU=ForUser1,DC=dom,DC=fr 
adspath : LDAP://WM2008R2ENT:389/CN=MonGrpDis,OU=ForUser1,DC=dom,DC=fr 
cn : MonGrpDis 
Find the user 1 

LDAP://WM2008R2ENT:389/CN=MonGrpPlusSec,OU=ForUser1,DC=dom,DC=fr 
adspath : LDAP://WM2008R2ENT:389/CN=MonGrpPlusSec,OU=ForUser1,DC=dom,DC=fr 
cn : MonGrpPlusSec 
Find the user 0 

LDAP://WM2008R2ENT:389/CN=MonGrpPlusSecUniv,OU=ForUser1,DC=dom,DC=fr 
adspath : LDAP://WM2008R2ENT:389/CN=MonGrpPlusSecUniv,OU=ForUser1,DC=dom,DC=fr 
cn : MonGrpPlusSecUniv 
Find the user 0 

(संपादित) '1.2.840.113556.1.4.1941' W2K3 SP1 में काम नहीं कर रहा है, यह SP2 के साथ काम करने के लिए शुरू होता है । मुझे लगता है कि यह W2K3 R2 के साथ समान है। यह W2K8 पर काम करना चाहिए। मैं यहां W2K8R2 के साथ परीक्षण करता हूं। मैं जल्द ही W2K8 पर इसका परीक्षण कर पाऊंगा।

+1

इसे साझा करने के लिए धन्यवाद।यह बहुत ही आशाजनक लग रहा है। मैं जहाँ मैं इसे तुरंत परीक्षण कर सकते हैं से दूर कर रहा हूँ (मुश्किल से इंटरनेट है) लेकिन मैं जितनी जल्दी हो सके यह परीक्षण करने और आप जानते हैं कि मैं क्या लगता है दूँगा। एक बार फिर धन्यवाद। – IAmTimCorey

+0

संपादित: मैं कुछ और जांच करने के लिए और से जब माइक्रोसॉफ्ट इन पुनरावर्ती नियंत्रण का समर्थन करने के लिए शुरू विवरण जोड़ें। मुझे अजीब बात है कि सूचना रूट डीएसई में नहीं है। – JPBlanc

+0

तो। क्या आप इसका परीक्षण करते हैं? – JPBlanc

6

अगर वहाँ कोई रास्ता नहीं है पुनरावर्ती कॉल के अलावा अन्य है (और मैं नहीं मानता है) तो कम से कम आप कर सकते हैं ढांचा है कि आप के लिए काम करते: UserPrincipal.GetAuthorizationGroups method देखना (System.DirectoryServices.AccountManagement नाम स्थान में और नेट में पेश 3,5)

इस विधि सभी समूहों रिकर्सिवली खोज करता है और में समूहों देता है जो उपयोगकर्ता एक सदस्य है। लौटे सेट भी अतिरिक्त समूह है कि सिस्टम उपयोगकर्ता प्रमाणीकरण उद्देश्यों के लिए के एक सदस्य पर विचार करेगा शामिल हो सकते हैं।

("समूह वस्तुओं है कि जिस भी समूह के वर्तमान प्रमुख सदस्य है, निर्दिष्ट का एक संग्रह रिटर्न")GetGroupsके परिणामों के साथ तुलना करें देखने के लिए कि सदस्यता स्पष्ट या अस्पष्ट है।

+0

उत्तर के लिए धन्यवाद:

संबंधित जवाब यहाँ देखें। इस विधि का परीक्षण करने में कुछ समस्याएं आईं। सबसे पहले, यह कुछ ऐसे समूह प्राप्त करता है जिन्हें आम तौर पर समूहों के रूप में सूचीबद्ध नहीं किया जाता है (जैसे "मध्यम अनिवार्य स्तर" या उसके करीब कुछ)। दूसरा, यह केवल सुरक्षा समूह (वितरण समूह नहीं) प्राप्त करता है। दुर्भाग्य से, मुझे दोनों की जरूरत है, हालांकि यदि वितरण समूह प्राप्त करने के लिए एक समान विधि थी, तो यह बहुत अच्छा होगा क्योंकि यह और भी दानेदार हो सकता है। – IAmTimCorey

2

एलडीएपी फ़िल्टर को दोबारा उपयोग करें लेकिन राउंड ट्रिप की संख्या को कम करने के लिए प्रत्येक क्वेरी के बाद लौटाए गए सभी समूहों के लिए क्वेरी करें।

पूर्व:

  1. सभी समूहों जहाँ उपयोगकर्ता एक सदस्य
  2. है जाओ सभी समूहों जहां चरण 1 समूहों के सदस्यों को
  3. सभी समूहों जाओ हैं जाओ जहां चरण 2 समूहों के सदस्यों को
  4. रहे हैं ...

मेरे अनुभव में शायद ही कभी 5 से अधिक हैं लेकिन निश्चित रूप से 30 से कम होना चाहिए।

012 इसके अलावा

:

  • केवल गुण तुम वापस की जरूरत करने जा रहे हैं खींचने के लिए सुनिश्चित करें।
  • कैशिंग परिणाम प्रदर्शन में काफी मदद कर सकते हैं लेकिन मेरे कोड को अधिक जटिल बना दिया गया है।
  • कनेक्शन पूलिंग का उपयोग करना सुनिश्चित करें।
  • प्राथमिक समूह अलग से नियंत्रित किया जा करने के लिए
+0

यह एक अच्छा विचार है। सहायता के लिए धन्यवाद। – IAmTimCorey

0
static List<SearchResult> ad_find_all_members(string a_sSearchRoot, string a_sGroupDN, string[] a_asPropsToLoad) 
    { 
     using (DirectoryEntry de = new DirectoryEntry(a_sSearchRoot)) 
      return ad_find_all_members(de, a_sGroupDN, a_asPropsToLoad); 
    } 

    static List<SearchResult> ad_find_all_members(DirectoryEntry a_SearchRoot, string a_sGroupDN, string[] a_asPropsToLoad) 
    { 
     string sDN = "distinguishedName"; 
     string sOC = "objectClass"; 
     string sOC_GROUP = "group"; 
     string[] asPropsToLoad = a_asPropsToLoad; 
     Array.Sort<string>(asPropsToLoad); 
     if (Array.BinarySearch<string>(asPropsToLoad, sDN) < 0) 
     { 
      Array.Resize<string>(ref asPropsToLoad, asPropsToLoad.Length+1); 
      asPropsToLoad[asPropsToLoad.Length-1] = sDN; 
     } 
     if (Array.BinarySearch<string>(asPropsToLoad, sOC) < 0) 
     { 
      Array.Resize<string>(ref asPropsToLoad, asPropsToLoad.Length+1); 
      asPropsToLoad[asPropsToLoad.Length-1] = sOC; 
     } 

     List<SearchResult> lsr = new List<SearchResult>(); 

     using (DirectorySearcher ds = new DirectorySearcher(a_SearchRoot)) 
     { 
      ds.Filter = "(&(|(objectClass=group)(objectClass=user))(memberOf=" + a_sGroupDN + "))"; 
      ds.PropertiesToLoad.Clear(); 
      ds.PropertiesToLoad.AddRange(asPropsToLoad); 
      ds.PageSize = 1000; 
      ds.SizeLimit = 0; 
      foreach (SearchResult sr in ds.FindAll()) 
       lsr.Add(sr); 
     } 

     for(int i=0;i<lsr.Count;i++) 
      if (lsr[i].Properties.Contains(sOC) && lsr[i].Properties[sOC].Contains(sOC_GROUP)) 
       lsr.AddRange(ad_find_all_members(a_SearchRoot, (string)lsr[i].Properties[sDN][0], asPropsToLoad)); 

     return lsr; 
    } 

    static void Main(string[] args) 
    { 
    foreach (var sr in ad_find_all_members("LDAP://DC=your-domain,DC=com", "CN=your-group-name,OU=your-group-ou,DC=your-domain,DC=com", new string[] { "sAMAccountName" })) 
     Console.WriteLine((string)sr.Properties["distinguishedName"][0] + " : " + (string)sr.Properties["sAMAccountName"][0]); 
    } 
2

आप tokenGroups और tokenGroupsGlobalAndUniversal गुण का उपयोग कर सकते है अगर आप Exchange सर्वर पर हैं। tokenGroups आप सभी सुरक्षा समूह इस प्रयोक्ता के अंतर्गत आता है, नेस्टेड समूहों और डोमेन उपयोगकर्ता, उपयोगकर्ताओं, आदि tokenGroupsGlobalAndUniversal आप .NET 3.5 या उच्चतर उपयोग कर रहे हैं tokenGroups और वितरण समूहों

private void DoWorkWithUserGroups(string domain, string user) 
    { 
     var groupType = "tokenGroupsGlobalAndUniversal"; // use tokenGroups for only security groups 

     using (var userContext = new PrincipalContext(ContextType.Domain, domain)) 
     { 
      using (var identity = UserPrincipal.FindByIdentity(userContext, IdentityType.SamAccountName, user)) 
      { 
       if (identity == null) 
        return; 

       var userEntry = identity.GetUnderlyingObject() as DirectoryEntry; 
       userEntry.RefreshCache(new[] { groupType }); 
       var sids = from byte[] sid in userEntry.Properties[groupType] 
          select new SecurityIdentifier(sid, 0); 

       foreach (var sid in sids) 
       { 
        using(var groupIdentity = GroupPrincipal.FindByIdentity(userContext, IdentityType.Sid, sid.ToString())) 
        { 
         if(groupIdentity == null) 
          continue; // this group is not in the domain, probably from sidhistory 

         // extract the info you want from the group 
        } 
       } 
      } 
     } 
    } 
1

से सब कुछ शामिल होंगे सहित दे देंगे आप System.DirectoryServices.AccountManagement नामस्थान का उपयोग कर सकते हैं जो वास्तव में यह आसान बनाता है। Active Directory nested groups

संबंधित मुद्दे