はじめに
これまで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ステップです。
- OpenLDAPの起動
- PythonプログラムでOpenLDAPへの接続
- 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
ちなみに、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
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"の値が更新されます。
"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のビューだと、以下のような見た目になります。
まとめ
とりあえずは、PythonプログラムからOpenLDAPに接続&ユーザ情報を取得することができました。
OpenLDAPに保存されている他の属性値も出力すれば、ユーザ情報の一覧化には重宝しそうな印象です。