2016-06-01 2 views
0

私は、python-ldapを使ってgroupOfNamesのメンバーであるグループに属するすべてのLDAPユーザーアカウントのリストを取得する最良の方法を探しています。これは、ADではなくOpenLDAPサーバー上にあります。私は仕事をするが、実行するために永遠にかかる以下の関数を書いた。私は、python-ldapの中に私が気付いていない組み込み関数をいくつか持っていることを望んでいます。あるいは、これをもっと速く動かすために変更できるものがあります。もしそうでなければ、他の人がこのコードを役に立つと思うでしょう。助けをあらかじめありがとう!python-ldapでネストされたLDAPグループメンバーを取得

def get_nested_members(con, dn): 
    """ 
    Parameters 
    ---------- 
    con : LDAPObject 
     An authenticated python-ldap connection object 
    dn : string 
     The dn of the groupOfNames to be checked 

    Returns 
    ------- 
    members : list 
     A list of all accounts that are members of the given dn 
    """ 

    members = [] 
    searched = [] 
    to_search = [dn] 

    while len(to_search) > 0: 
     current_dn = to_search.pop() 
     cn = current_dn.split(',')[0] 
     r = con.search_s(base_dn, ldap.SCOPE_SUBTREE, cn, [])[0][1] 
     if 'groupOfNames' in r['objectClass']: 
      if 'member' in r: 
       for i in r['member']: 
        if((i != current_dn) and (i not in searched)): 
         to_search.append(i) 
      searched.append(current_dn) 
     elif 'posixGroup' in r['objectClass']: 
      if 'memberUid' in r: 
       for i in r['memberUid']: 
        members.append(i) 
      searched.append(current_dn) 
     elif 'posixAccount' in r['objectClass']: 
      if 'uid' in r: 
       members.append(r['uid'][0]) 
     else: 
      print('ERROR: encountered record of unknown type:') 
      pprint(str([current_dn, r])) 
    return list(set(members)) 
+0

LDAPツリーの構造に応じて、あなたはこのアルゴリズムは、おそらくエントリ複数回の多くの重複セットを検索してもよいと思われるよう 'ldap.SCOPE_BASE'を使用して試してみたいことがあります。また、 '(|(objectClass = groupOfNames)(objectclass = posixGroup)(objectclass = posixAccount))'のようなLDAPフィルタを使って検索を制限することもできます。また、返す属性を指定することもできます(属性のサブセットが各検索で返されるように)。 'member'、' memberUid'および 'uid'属性のみを要求します。 –

答えて

0

私は繰り返しのldapsearchを実行すると、制限要因だったことに気づいたので、私は最初にすべてのグループやgroupOfNamesのレコードの辞書を構築し、新しいバージョンを作りました。これは従来のソリューションよりも少しメモリが必要ですが、LDAPサーバーへの課金が少なく、大幅に高速に実行されます(アプリケーションの場合は15分から<に1秒まで)。私は何をするべきではないかについての参考のために、新しいバージョンの下に元のコードを残しておきます。 merge_dicts()関数のクレジットはAaron Hallになります。

import ldap 

def merge_dicts(*dict_args): 
    """Given any number of dicts, shallow copy and merge into a new dict, 
    precedence goes to key value pairs in latter dicts. 
    """ 

    result = {} 
    for dictionary in dict_args: 
     result.update(dictionary) 
    return result 


def get_nested_members(con, dn, base_dn='dc=example'): 
    """Search a groupOfNames and return all posixAccount members from all its subgroups 

    Parameters 
    ---------- 
    con: LDAPObject 
     An authenticated LDAP connection object 
    dn: string 
     The dn of the groupOfNames to be searched for members 
    (optional) base_dn: string 
     The base dn to search on. Make sure to change the default value to fit your LDAP server 

    Returns 
    ------- 
    members: list 
     A list of all nested members from the provided groupOfNames 
    """ 

    logging.info('Getting nested members of ' + str(dn)) 
    print('Getting nested members of ' + str(dn)) 

    if type(dn) is list: 
     to_search = [] + dn 
    elif type(dn) is str: 
     to_search = [dn] 
    else: 
     print('ERROR: Invalid dn value. Please supply either a sting or list of strings.') 
     return [] 

    members = [] 
    searched = [] 

    groupOfNames_list = con.search_s(base_dn, ldap.SCOPE_SUBTREE, 'objectClass=groupOfNames', ['dn', 'member', 'cn']) 
    groupOfNames_dict = {} 
    for g in range(len(groupOfNames_list)): 
     groupOfNames_dict[groupOfNames_list[g][0]] = groupOfNames_list[g][1] 
    groupOfNames_list = None #To free up memory 

    group_list = con.search_s(base_dn, ldap.SCOPE_SUBTREE, 'objectClass=posixGroup', ['dn', 'memberUid', 'cn']) 
    group_dict = {} 
    for g in range(len(group_list)): 
     group_dict[group_list[g][0]] = group_list[g][1] 
    group_list = None #To free up memory 

    all_groups = merge_dicts(groupOfNames_dict, group_dict) 
    group_dict = None #To free up memory 
    groupOfNamesdict = None #To free up memory 

    while len(to_search) > 0: 
     search_dn = to_search.pop() 
     try: 
      g = all_groups[search_dn] 
      if 'memberUid' in g: 
       members += g['memberUid'] 
       searched.append(search_dn) 
      elif 'member' in g: 
       m = g['member'] 
       for i in m: 
        if i.startswith('uid='): 
         members.append((i.split(',')[0]).split('=')[1]) 
        elif i.startswith('cn='): 
         if i not in searched: 
          to_search.append(i) 
       searched.append(search_dn) 
      else: 
       searched.append(search_dn) 
     except: 
      searched.append(search_dn) 
    return list(set(members)) 
関連する問題