pythonのldap3でactive directoryのユーザ情報を検索する方法

スポンサードリンク



こんにちは。sinyです。

この記事では、pythonのldap3というライブラリーを使ってActive Directoryのユーザ情報を検索する方法をご紹介します。

LDAP3とは?

ldap3とは、2006年6月にリリースされた公式RFCに準拠した完全準拠のLDAP v3クライアントライブラリです。
Python 2およびPython 3と互換性があり、Pythonの標準ライブラリ経由でLDAPサーバにアクセスすることができます。

ある程度の規模の企業でシステム管理に関わっている方であれば、LDAPからユーザ情報を取得したいといった要件が発生することがあると思います。

そんな時は、このpythnoライブラリであるldap3を使うと簡単にActive Directory上のユーザ情報を検索して情報を収集することができます。

ldap3ライブラリーの利用方法

ldap3を利用してActive Directoryからユーザ情報を検索する方法は以下の通りです。

事前準備

まず最初に、以下のコマンドでldap3をインストールします。

pip install ldap3

 

LDAPサーバへ接続

続いて、DLAPサーバへ接続するサンプルコードです。

from ldap3 import Server, Connection, ALL, NTLM,SUBTREE
server = Server('LDAPサーバ名', get_info=ALL)
conn = Connection(server, user='ドメイン名\ユーザ名', password='パスワード', check_names=True, read_only=True, auto_bind=True)
1行目:必要なモジュールをインポートします。
2行目:接続先のLDAPサーバ情報をserver変数に定義します。
    ※Serverには接続先のLDAPサーバを指定します。
3行目:server変数を利用して、LDAPサーバとの接続を確立します。
    以下のuserとpasswordにはLDAPサーバにアクセスする際のLDAPサーバ側のユーザ認証情報を指定します。
    ※user='ドメイン名\ユーザ名', password='パスワード

LDAPサーバに接続できているかどうかは、以下のコマンドで確認できます。

conn.extend.standard.who_am_i()

正常に接続できている場合は、「'u:ドメイン名\\ユーザ名'」という感じで認証済みのユーザ名が表示されます。

LDAPサーバ上のユーザ情報検索

ldap3を使った検索の最もシンプルな方法としてsearchメソッドがあります。

例えば、LDAPからユーザID、氏名、部門情報を抽出するには以下のようなコマンドを発行すればOKです。

conn.search('dc=xx,dc=xx,dc=xx', '(objectclass=person)', attributes=['cn', 'displayName', 'description'],paged_size=100))

 

  • objectclassはLDAPサーバ側のオブジェクトクラスを指定します。
    上記の例で指定している「Person」は人の定義を意味するオブジェクトクラスです。
    ※オブジェクトクラスとは属性の集合体のこと
  • attributesにはオブジェクトクラスから取得したい属性名を指定します。
  • paged_sizeに取得するエントリー数を指定。
 Microsoft Active Directoryの場合だと、検索結果は1000エントリまでしか返してくれないという制限があるため、1000件以上の情報を取得したい場合は、上記のserachメソッドだとうまく情報取得できません。
そのため、ADを扱うときは上記のようなシンプルな検索ではなく次に紹介するページ検索で実行する必要があります。

ページ検索による方法

一度に1000件以上のユーザ情報を取得したい場合は、searchメソッドではなく、ページ検索と呼ばれる方法を使います。

この方法であれば、1000件を超えるユーザ情報を一括で取得することができます。
また、ページ検索には以下の2つの方法があります。

  1. ジェネレータを利用する方法
    ⇒消費メモリが少なくパフォーマンスもよいが、ジェネレータは一回実行すると内容は消失してしまうので、内容を後から確認するには再実行する必要がある
  2. ジェネレータを使わずリスト形式で情報を取得する方法
    ⇒リストを使うと結果を一旦変数内に蓄積できるので、後から収集した情報を操作できる。
     ただし、ジェネレータに比べると処理速度はかなり遅くなります。

 

ジェネレータを利用する方法

ジェネレータを利用した検索方法のサンプルコードです。

entry_list = conn.extend.standard.paged_search(search_base = 'dc=xx,dc=xxxxxxx,dc=xxxxxxx', 
                                               search_filter = '(objectClass=person)', 
                                               attributes = ['cn', 'displayName', 'description'], 
                                               paged_size = 100, 
                                               generator=True)

 

extend.standard.paged_searchというメソッドを使いページ検索を行います。
ポイントは、「 generator=True」で、ジェネレータを有効化する点です。

 

ジェネレータを使わずリスト形式で情報を取得する方法

ジェネレータを使わずリスト形式で情報を取得する方法のサンプルコードです。

entry_list = conn.extend.standard.paged_search(search_base = 'dc=xx,dc=xxxxxxx,dc=xxxxxxx', 
                                               search_filter = '(objectClass=person)', 
                                               attributes = ['cn', 'displayName', 'description'], 
                                               paged_size = 100, 
                                               generator=False)

 

リスト形式の方法もextend.standard.paged_searchというメソッドを使いますが、ジェネレータの場合と違うのは、「 generator=False」の部分だけです。

今回は、このリスト形式の結果についてもう少し見ていきます。

上記コードを実行すると、戻り値として辞書のリストが返ってきます。

戻り値の例
{'raw_dn': b'CN=xxxx,OU=Disabled,DC=xx,DC=xxxxxx,DC=xxxxx', 'dn':
'CN=xxxx,OU=Disabled,DC=xx,DC=xxxxxx,DC=xxxxx', 'raw_attributes':
{'cn': [b'xxxxx'], 'description': [b'\~~~~省略~~'], 'displayName':
[b'~~省略~~']}, 'attributes': {'cn': 'xxxxx', 'description':
['~~部門情報~~'], 'displayName': '~氏名~'}, 'type': 'searchResEntry'}
戻り値には以下のカテゴリ情報が格納されています。
  • dn:エントリの識別名
  • attributes:返された属性とその値の辞書 値はリスト。 (値はUTF-8形式)
  • raw_attributes: 'attributes'と同じですが、エンコードされていない。(bytearray)
その他のポイント
  • 属性は、大文字と小文字を区別せずに内部辞書に格納されている。
  • 生の属性にアクセス →entry_raw_attribute(attribute_name)を使用する。
  • 生の属性の辞書全体を取得 →entry_raw_attributesを利用する。
  • エントリは読み取り専用オブジェクト
エントリの各属性は辞書または名前空間としてアクセスできます。
上記サンプルコードで取得したLDAP情報(entry_list )からユーザID、氏名、部門情報を取得する方法のサンプルコードは以下の通りです。
ldap_info = []												
for num, item in enumerate(entry_list):												
    if num > 3:												
        if item['attributes']['displayName'] and item['attributes']['description']:												
            ldap_info.append([item['attributes']['cn'],item['attributes']['displayName'] ,item['attributes']['description'][0]])												

※検証した際、最初の4行はユーザ情報じゃなかったので除外しています。

ldap_infoにはリスト形式で以下の情報が格納されます。

['ユーザID名', '氏名', '部門情報']

以下のようにすればCSVに吐き出せます。

with open('ldap_user.csv', 'w',newline='',encoding='cp932',errors='ignore') as f:				
    writer = csv.writer(f)				
    writer.writerows(ldap_info)				

 

以上、pythonのldap3でactive directoryのユーザ情報を検索する方法のご紹介でした。

この記事が良かったと思う方はTwitterフォロー(shiny)とリツイート頂けると嬉しいです!

おすすめの記事