2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

PythonプログラムからOpenLDAPに接続&ユーザ情報を取得する

Last updated at Posted at 2022-01-10

はじめに

これまでJupyterHub/JupyterLabを利用した分析環境をVirtualBoxもしくはWSL2で整備してきたが、共通して認証にはOpenLDAPを使ってきた。

自宅PCでは自ずと筆者のみの利用ではあるが、会社(組織)で利用するならばユーザ管理をする必要がある。
どれだけのユーザがいて、いつパスワード変更をしたか、etc.

というわけで、OpenLDAPに登録したユーザの情報を取得するプログラムを書いてみようと思う。
なぜプログラムか?かというと、OpenLDAP操作用のWebUIにはFusionDirectoryやphpLDAPadminがあるものの、全ユーザの情報を一覧で取得するのはちょっと面倒と思った次第でして。

そこで、本稿では、**「PythonプログラムからOpenLDAPに接続&ユーザ情報を取得する方法」**を順に紹介してゆく。

本稿で紹介すること

  • OpenLDAPの起動
  • PythonプログラムでOpenLDAPへの接続
  • PythonプログラムでOpenLDAPからユーザ情報の取得

本稿で紹介しないこと

  • WSL2のインストール
  • Ubuntuのインストール(From Microsoft Store) ※Ubuntu 18.04.5 LTSを使用
  • Dockerのインストール ※Docker Community Edition 20.10.8を使用
  • Pythonライブラリ(LDAP3)の全般
  • OpenLDAP操作用のWebUI(FusionDirectoryおよびphpLDAPadmin)の全般

過去の記事を参照されたし。

※1: Windows10のPCに分析環境(VirtualBox/Vagrant+Kubernetes+JupyterHub/JupyterLab)を作ってみた
※2: Windows10のPCに分析環境(VirtualBox/Vagrant+Docker+JupyterHub/JupyterLab)を作ってみた
※3: GPU搭載WindowsのWSL2でNGCカタログのコンテナイメージを使う
※4: SeleniumとMeCabを使えるJupyterLabコンテナイメージを作る

ステップ紹介

大きく、3ステップです。

  1. OpenLDAPの起動
  2. PythonプログラムでOpenLDAPへの接続
  3. PythonプログラムでOpenLDAPからユーザ情報の取得

事前準備

以下、筆者の環境です。

$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.5 LTS"
$ docker version
Client: Docker Engine - Community
 Version:           20.10.8
 API version:       1.41
 Go version:        go1.16.6
 Git commit:        3967b7d
 Built:             Fri Jul 30 19:54:08 2021
 OS/Arch:           linux/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.8
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.16.6
  Git commit:       75249d8
  Built:            Fri Jul 30 19:52:16 2021
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.4.9
  GitCommit:        e25210fe30a0a703442421b0f60afac609f950a3
 nvidia:
  Version:          1.0.1
  GitCommit:        v1.0.1-0-g4144b63
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0

本稿ではhrektts/fusiondirectory-openldap:1.1.9-1.2-1を取得&起動し、ユーザ管理に利用するものとします。
また、過去の記事(※4)でビルドしたjupyter/minimal-notebook:9e8682c9ea54-MeCab-Slumを起動し、Pythonプログラムの実行に利用するものとします。

$ docker images
REPOSITORY                         TAG                       IMAGE ID       CREATED         SIZE
jupyterhub/jupyterhub              1.0-gpu                   e7dd44e871bd   3 days ago      420MB
jupyter/minimal-notebook           9e8682c9ea54-MeCab-Slum   a2645c7160be   4 days ago      3.92GB
jupyter/minimal-notebook           9e8682c9ea54-MeCab        d0e1a0e79bc8   4 days ago      3.55GB
postgres                           9.6                       131ab388dac1   4 months ago    200MB
nvcr.io/nvidia/pytorch             20.11-py3-gpu             dd53c8b61c4b   5 months ago    15.3GB
nvcr.io/nvidia/tensorflow          20.11-tf2-py3-gpu         f6aa8098fc48   5 months ago    12.3GB
adminer                            4.8.1                     4727f36d62d9   5 months ago    90MB
nvcr.io/nvidia/tensorflow          21.07-tf2-py3             887093b5693e   5 months ago    11.1GB
nvcr.io/nvidia/pytorch             21.07-py3                 7beec3ff8d35   5 months ago    15GB
nvcr.io/nvidia/tensorflow          20.11-tf2-py3             98a7952f7f9c   14 months ago   11.6GB
nvcr.io/nvidia/pytorch             20.11-py3                 ae35b2b3cad1   14 months ago   13.2GB
jupyterhub/jupyterhub              1.0                       c399e04fda3c   2 years ago     283MB
osixia/phpldapadmin                0.9.0                     78148b61fdb5   2 years ago     302MB
jupyter/minimal-notebook           2343e33dec46              c3bbd3471e39   3 years ago     2.72GB
jupyter/minimal-notebook           9e8682c9ea54              400c44c4a7a7   3 years ago     2.79GB
hrektts/fusiondirectory-openldap   1.1.9-1.2-1               7f2e4370509d   4 years ago     226MB
hrektts/fusiondirectory            0.2.0                     b56f1086a08d   4 years ago     345MB

1. OpenLDAPの起動

本ステップは、WSL上で実行

以下のリンクに記載された手順を見本とし、起動します。
hrektts/fusiondirectory-openldap
hrektts/fusiondirectory
osixia/phpldapadmin

以下、環境設定(環境変数の定義)を含む起動コマンドです。

$ docker run --name ldap -p 389:389 \
  -e LDAP_ORGANISATION="OpenLDAP for ldapauthenticator.LDAPAuthenticator" \
  -e LDAP_DOMAIN="hoge.com" \
  -e LDAP_ADMIN_PASSWORD="ldapadminpwd" \
  -e FD_ADMIN_PASSWORD="fdadminpwd" \
  -d hrektts/fusiondirectory-openldap:1.1.9-1.2-1

ちなみに、FusionDirectoryの起動コマンドはこちら。
Webブラウザで http://127.0.0.1/fd/ にアクセスし、Usernameに「fd-admin」、Passwordに上述の「FD_ADMIN_PASSWORD」に指定した文字列でログインできればOKです。

本稿では、予めFusionDirectoryを操作し、「jhub」OUを作成&3ユーザを作成するものとします。

$ docker run --name fd -p 80:80 --link ldap:ldap \
  -d hrektts/fusiondirectory:0.2.0

image.png

ちなみに、phpLDAPadminの起動コマンドはこちら。
Webブラウザで http://127.0.0.1:8080 にアクセスし、Login DNに「cn=admin,dc=hoge,dc=com」、Passwordに上述の「LDAP_ADMIN_PASSWORD」に指定した文字列でログインできればOKです。

$ docker run --name phpldapadmin \
  --hostname phpldapadmin-service \
  --link ldap:ldap-host \
  --env PHPLDAPADMIN_LDAP_HOSTS=ldap-host \
  --restart=always \
  --publish=8443:443 \
  --publish=8080:80 \
  --env PHPLDAPADMIN_HTTPS=false \
  --detach osixia/phpldapadmin:0.9.0

image.png

2. PythonプログラムでOpenLDAPへの接続

本ステップは、JupyterLab上で実行

以下、PythonとPIPのVer情報です。

$ python -V
Python 3.6.6
$ python -m pip --version
pip 21.2.2 from /opt/conda/lib/python3.6/site-packages/pip (python 3.6)

以下、必要なPythonライブラリのインストールコマンドです。(PIPが古くなってますね、、、気になる方はUpgradeをば。)

$ python -m pip install ldap3
Requirement already satisfied: ldap3 in /opt/conda/lib/python3.6/site-packages (2.7)
Requirement already satisfied: pyasn1>=0.1.8 in /opt/conda/lib/python3.6/site-packages (from ldap3) (0.4.8)
WARNING: You are using pip version 21.2.2; however, version 21.3.1 is available.
You should consider upgrading via the '/opt/conda/bin/python -m pip install --upgrade pip' command.

以下、OpenLDAPへの接続Code例です。

OpenLDAPのIPアドレス、ポート番号、SSL接続有無は、読者の環境に合わせて書き換えてください。

from ldap3 import Server, Connection, ALL, NTLM, SUBTREE, ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES
server = Server('${OpenLDAPのIPアドレス}', get_info=ALL, port=389, use_ssl=False)
conn = Connection(server, user='cn=admin,dc=hoge,dc=com', password='ldapadminpwd', auto_bind=True)

接続確立後、接続に指定したuserのDN文字列が表示できればOKです。

conn.extend.standard.who_am_i()
# 'dn:cn=admin,dc=hoge,dc=com'

3. PythonプログラムでOpenLDAPからユーザ情報の取得

本ステップは、JupyterLab上で実行

以下、OpenLDAPからユーザ情報の取得Code例です。

OpenLDAPの階層(OU)は、読者の環境に合わせて書き換えてください。

LDAPクエリを実行し、Trueが表示できればOKです。

conn.search('ou=people,ou=jhub,dc=hoge,dc=com', '(objectclass=person)', attributes=[ALL_ATTRIBUTES, ALL_OPERATIONAL_ATTRIBUTES], paged_size=100, search_scope=SUBTREE)
# True

検索結果をPrintしてみます。

for entry in sorted(conn.entries):
    print(entry.entry_dn)
    print(entry.entry_raw_attribute)

今回は、「jhub」OUの配下の全ユーザの情報が出力されます。

uid=admin,ou=people,ou=jhub,dc=hoge,dc=com
<bound method EntryBase.entry_raw_attribute of DN: uid=admin,ou=people,ou=jhub,dc=hoge,dc=com - STATUS: Read - READ TIME: 2022-01-10T12:51:16.304321
    cn: admin jupyterhub
    createTimestamp: 2022-01-10 12:43:49+00:00
    creatorsName: cn=admin,dc=hoge,dc=com
    entryCSN: 20220110124409.081861Z#000000#000#000000
    entryUUID: b44f782e-065e-103c-9bc3-61c9f2a130f0
    givenName: admin
    hasSubordinates: False
    modifiersName: cn=admin,dc=hoge,dc=com
    modifyTimestamp: 2022-01-10 12:44:09+00:00
    objectClass: inetOrgPerson
                 organizationalPerson
                 person
    sn: jupyterhub
    structuralObjectClass: inetOrgPerson
    subschemaSubentry: cn=Subschema
    uid: admin
    userPassword: b'{SSHA}cnvbA3tVbuxbCZYyafChFw6qV3ZLlfv/'
>
uid=user1,ou=people,ou=jhub,dc=hoge,dc=com
<bound method EntryBase.entry_raw_attribute of DN: uid=user1,ou=people,ou=jhub,dc=hoge,dc=com - STATUS: Read - READ TIME: 2022-01-10T12:51:16.303493
    cn: user1 jupyterhub
    createTimestamp: 2022-01-10 12:41:50+00:00
    creatorsName: cn=admin,dc=hoge,dc=com
    entryCSN: 20220110124150.915437Z#000000#000#000000
    entryUUID: 6d5d2ba0-065e-103c-9bbf-61c9f2a130f0
    givenName: user1
    hasSubordinates: False
    modifiersName: cn=admin,dc=hoge,dc=com
    modifyTimestamp: 2022-01-10 12:41:50+00:00
    objectClass: inetOrgPerson
                 organizationalPerson
                 person
    sn: jupyterhub
    structuralObjectClass: inetOrgPerson
    subschemaSubentry: cn=Subschema
    uid: user1
    userPassword: b'{SSHA}VAHOD9cryu8XfEcX/Q99/k2Tvoqg8E/B'
>
uid=user2,ou=people,ou=jhub,dc=hoge,dc=com
<bound method EntryBase.entry_raw_attribute of DN: uid=user2,ou=people,ou=jhub,dc=hoge,dc=com - STATUS: Read - READ TIME: 2022-01-10T12:51:16.303761
    cn: user2 jupyterhub
    createTimestamp: 2022-01-10 12:42:22+00:00
    creatorsName: cn=admin,dc=hoge,dc=com
    entryCSN: 20220110124222.193645Z#000000#000#000000
    entryUUID: 8001d8a0-065e-103c-9bc0-61c9f2a130f0
    givenName: user2
    hasSubordinates: False
    modifiersName: cn=admin,dc=hoge,dc=com
    modifyTimestamp: 2022-01-10 12:42:22+00:00
    objectClass: inetOrgPerson
                 organizationalPerson
                 person
    sn: jupyterhub
    structuralObjectClass: inetOrgPerson
    subschemaSubentry: cn=Subschema
    uid: user2
    userPassword: b'{SSHA}JTT6fLPXEsdfOLgPNI4WSBIKUjJ6uEL+'
>
uid=user3,ou=people,ou=jhub,dc=hoge,dc=com
<bound method EntryBase.entry_raw_attribute of DN: uid=user3,ou=people,ou=jhub,dc=hoge,dc=com - STATUS: Read - READ TIME: 2022-01-10T12:51:16.304017
    cn: user3 jupyterhub
    createTimestamp: 2022-01-10 12:42:40+00:00
    creatorsName: cn=admin,dc=hoge,dc=com
    entryCSN: 20220110124240.888741Z#000000#000#000000
    entryUUID: 8b267dd0-065e-103c-9bc1-61c9f2a130f0
    givenName: user3
    hasSubordinates: False
    modifiersName: cn=admin,dc=hoge,dc=com
    modifyTimestamp: 2022-01-10 12:42:40+00:00
    objectClass: inetOrgPerson
                 organizationalPerson
                 person
    sn: jupyterhub
    structuralObjectClass: inetOrgPerson
    subschemaSubentry: cn=Subschema
    uid: user3
    userPassword: b'{SSHA}qCTxg7K1DaelVbKfkL/1twiQEPCcCpxD'
>

もう一息!

以下、取得済みのユーザ情報のCSVファイル出力Code例です。

3列構成("uid":ユーザ名、"createTimestamp":登録日時、"modifyTimestamp":更新日時≒最終パスワード変更日時)です。

import codecs

f = codecs.open('users.csv', 'w', 'utf-8')
f.write('"uid","createTimestamp","modifyTimestamp"\n')
for entry in sorted(conn.entries):
    f.write('%s,%s,%s\n' %(str(entry['uid']), str(entry['createTimestamp']), str(entry['modifyTimestamp'])))
f.close()

パスワード変更をすると、"modifyTimestamp"の値が更新されます。

users.csv
"uid","createTimestamp","modifyTimestamp"
admin,2022-01-10 12:43:49+00:00,2022-01-10 14:38:53+00:00
user1,2022-01-10 12:41:50+00:00,2022-01-10 12:41:50+00:00
user2,2022-01-10 12:42:22+00:00,2022-01-10 12:42:22+00:00
user3,2022-01-10 12:42:40+00:00,2022-01-10 12:42:40+00:00

JupyterLabのCSTTableのビューだと、以下のような見た目になります。
image.png

まとめ

とりあえずは、PythonプログラムからOpenLDAPに接続&ユーザ情報を取得することができました。
OpenLDAPに保存されている他の属性値も出力すれば、ユーザ情報の一覧化には重宝しそうな印象です。

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?