簡體   English   中英

使用python-ldap獲取嵌套的LDAP組成員

[英]Get nested LDAP group members with python-ldap

我正在嘗試找到最佳方法,以使用python-ldap獲取屬於組的所有LDAP用戶帳戶的列表,這些組是groupOfNames的成員。 這是在OpenLDAP服務器上,而不是AD上。 我在下面編寫了函數,該函數可以完成工作,但要花很長時間才能運行。 我希望python-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))

我意識到反復運行ldapsearch是限制因素,因此我制作了一個新版本,該版本首先構建了ALL group和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))

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM