原文轉(zhuǎn)載自「劉悅的技術(shù)博客」https://v3u.cn/a_id_180
OpenLdap(Lightweight Directory Access Protocol)是什么?它其實是一個開源的、具備工業(yè)標(biāo)準(zhǔn)特性的應(yīng)用協(xié)議,可以使用TCP協(xié)議提供訪問控制和維護分布式信息的目錄信息。這是一個傳統(tǒng)意義上的書面解釋,是的,毫無疑問,你會一臉懵逼。好吧,讓我們變得感性一點,假如我每天早上使用Twitter想聽聽懂王又吹了什么牛,登錄Twitter賬號密碼,緊接著又想上Instagram看看女神又post了什么新靚照,好的,登錄Instagram賬號密碼,摸了一上午的魚之后,突然想起來要登錄公司的郵箱,看看有沒有新需求,是的,又需要那該死的賬號和密碼,甚至于查詢社保、公積金提取、交罰款都需要各自系統(tǒng)的賬號和密碼。想象一下,如果有一套系統(tǒng)可以統(tǒng)一管理和維護所有下游應(yīng)用的賬號和權(quán)限,我們不需要花時間重復(fù)的注冊新應(yīng)用的賬號,而只需要關(guān)注應(yīng)用本身,從而實現(xiàn)賬號集中認(rèn)證管理,此時作為賬號管理員的我們只須維護OpenLDAP 服務(wù)器條目即可,金甌無缺江山一統(tǒng),這就是openladp能夠帶給我們的好處。
LDAP是非常典型的層級結(jié)構(gòu),信息模型是建立在屬性條目(entries)的基礎(chǔ)上。一個屬性條目是一些屬性的集合,并且具有一個全局唯一的"可區(qū)分名稱"DN,一個條目可以通過DN來引用。每一個條目的屬性具有一個類型和一個或者多個值。類型通常是容易記憶的名稱,比如"cn"是通用名稱(common name) ,或者"mail"是電子郵件地址。條目的值的語法取決于屬性類型。比如,cn屬性可能具有一個值"jack joe" 。一個mail屬性可能包含"admin@v3u.cn" 。一個pngphoto屬性可能包含一幅PNG(二進制)格式的圖片。
這里簡單介紹一下openldap常用的層級關(guān)鍵字的解釋:
dc:Domain Component 域名的范圍,其格式是將完整的域名分成幾部分,如域名為v3u.cn則寫成dc=v3u,dc=cn。
uid:User Id 用戶ID,比如自增長“1”。
ou:Organization Unit 組織單位,類似于文件系統(tǒng)中的子目錄,它是一個容器對象,組織單位可以包含其他各種對象(包括其他組織單元),如“newgroup”。
cn:Common Name 公共名稱,如“jack joe”。
sn: Surname 姓,如“joe”。
dn :Distinguished Name 惟一辨別名,類似于文件系統(tǒng)中的絕對路徑,每個對象都有一個惟一的名稱,類似于mysql的全局唯一索引,如“uid= tom,ou=market,dc=example,dc=com”,記住在一個目錄樹中DN總是惟一的。
理解了概念,讓我們來實操一把,因為實踐永遠(yuǎn)是檢驗真理的唯一標(biāo)準(zhǔn),首先安裝Docker,參照:win10系統(tǒng)下把玩折騰DockerToolBox以及更換國內(nèi)鏡像源(各種神坑)。
隨后拉取openldap鏡像:
docker pull osixia/openldap:1.3.0
這里我們使用1.3穩(wěn)定版,拉取成功后查看本地鏡像
docker images
可以看到只有200mb左右,非常小巧:
liuyue:~ liuyue$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
osixia/openldap 1.3.0 faac9bb59f83 6 months ago 260MB
啟動容器:
docker run -p 389:389 --name myopenldap --network bridge --hostname openldap-host --env LDAP_ORGANISATION="v3u" --env LDAP_DOMAIN="v3u.cn" --env LDAP_ADMIN_PASSWORD="admin" --detach osixia/openldap:1.3.0
這里我們通過端口映射將389端口作為鏈接橋梁,同時配置LDAP組織者:--env LDAP_ORGANISATION="v3u",配置LDAP域:--env LDAP_DOMAIN="v3u.cn",配置LDAP密碼:--env LDAP_ADMIN_PASSWORD="admin",默認(rèn)登錄用戶名:admin,并且開啟后臺守護進程。
查看容器運行狀態(tài):
docker ps
可以看到已經(jīng)在后臺啟動了:
liuyue:~ liuyue$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b62d1f66c2b8 osixia/openldap:1.3.0 "/container/tool/run" 2 days ago Up 2 days 0.0.0.0:389->389/tcp, 636/tcp myopenldap
liuyue:~ liuyue$
服務(wù)確認(rèn)沒問題之后,我們通過python來進行邏輯的編寫,首先安裝依賴
pip3 install ldap3
隨后編寫測試腳本 test_ldap.py ,首先測試一下鏈接ldap服務(wù)器:
from ldap3 import Server, Connection, ALL,MODIFY_REPLACE
s = Server('localhost', get_info=ALL)
c = Connection(s, user='cn=admin,dc=v3u,dc=cn', password='admin')
c.bind()
print(c.extend.standard.who_am_i())
這里的localhost是docker容器的ip,同時使用賬號admin登錄,注意賬號(cn)以及域(dc)不要寫錯,不出意外的話,系統(tǒng)會返回當(dāng)前驗證的用戶信息:
liuyue:mytornado liuyue$ python3 "/Users/liuyue/wodfan/work/mytornado/test_ldap.py"
dn:cn=admin,dc=v3u,dc=cn
liuyue:mytornado liuyue$
初始狀態(tài)下,LDAP是一個空目錄,即沒有任何數(shù)據(jù)。可通過程序代碼向目錄數(shù)據(jù)庫中添加數(shù)據(jù),也可使用ldap3庫的ldapadd命令來完成添加數(shù)據(jù)的操作,該命令可將一個LDIF文件中的條目添加到目錄:
這里我們來添加一個OU,也就是組織(OrganizationalUnit)。
#添加組織
res = c.add('OU=v3u_users,dc=v3u,dc=cn', object_class='OrganizationalUnit')
print(res)
print(c.result)
可以看到添加成功:
liuyue:mytornado liuyue$ python3 "/Users/liuyue/wodfan/work/mytornado/test_ldap.py"
True
{'result': 0, 'description': 'success', 'dn': '', 'message': '', 'referrals': None, 'type': 'addResponse'}
隨后可以為該組織添加一個群組(group):
# 添加群組
ldap_attr = {}
ldap_attr['objectClass'] = ['top', 'posixGroup']
ldap_attr['gidNumber'] = '1'
c.add('cn=mygroup,dc=v3u,dc=cn',attributes=ldap_attr)
print(c.result)
返回:
liuyue:mytornado liuyue$ python3 "/Users/liuyue/wodfan/work/mytornado/test_ldap.py"
{'result': 0, 'description': 'success', 'dn': '', 'message': '', 'referrals': None, 'type': 'addResponse'}
liuyue:mytornado liuyue$
緊接著就是添加人員了:
#添加用戶
ldap_attr = {}
ldap_attr['cn'] = "test user1"
ldap_attr['sn'] = "測試"
ldap_attr['userPassword'] = "1234"
user_dn = "cn=testuser1,cn=mygroup,dc=v3u,dc=cn"
c.add(dn=user_dn,object_class='inetOrgPerson',attributes=ldap_attr)
print(c.result)
這里的cn可以理解為用戶名,sn為姓,userPassword顧名思義就是該用戶的密碼,dn則是該用戶在系統(tǒng)中的唯一標(biāo)識,注意指定剛剛建立的群組mygroup,返回:
liuyue:mytornado liuyue$ python3 "/Users/liuyue/wodfan/work/mytornado/test_ldap.py"
{'result': 0, 'description': 'success', 'dn': '', 'message': '', 'referrals': None, 'type': 'addResponse'}
liuyue:mytornado liuyue$
此時,我們可以查詢一下剛剛建立好的用戶:
print(c.search("dc=v3u,dc=cn", '(&(cn=testuser1))', attributes=['*']))
print(c.entries)
就可以看到用戶的具體信息:
liuyue:mytornado liuyue$ python3 "/Users/liuyue/wodfan/work/mytornado/test_ldap.py"
True
[DN: cn=testuser1,cn=mygroup,dc=v3u,dc=cn - STATUS: Read - READ TIME: 2020-11-23T17:58:08.569044
cn: test user1
testuser1
objectClass: inetOrgPerson
sn: 測試
userPassword: b'1234'
]
liuyue:mytornado liuyue$
如果我們要修改用戶信息,可以使用modify方法:
#修改用戶
c.modify('cn=testuser1,cn=mygroup,dc=v3u,dc=cn',{'uid':[(MODIFY_REPLACE, ['1'])]})
print(c.result)
這里修改用戶的uid屬性,返回:
liuyue:mytornado liuyue$ python3 "/Users/liuyue/wodfan/work/mytornado/test_ldap.py"
{'result': 0, 'description': 'success', 'dn': '', 'message': '', 'referrals': None, 'type': 'modifyResponse'}
liuyue:mytornado liuyue$
再次搜索該用戶:
print(c.search("dc=v3u,dc=cn", '(&(cn=testuser1))', attributes=['*']))
print(c.entries)
可以看到uid已經(jīng)被添加好了:
liuyue:mytornado liuyue$ python3 "/Users/liuyue/wodfan/work/mytornado/test_ldap.py"
True
[DN: cn=testuser1,cn=mygroup,dc=v3u,dc=cn - STATUS: Read - READ TIME: 2020-11-23T18:02:47.080555
cn: test user1
testuser1
objectClass: inetOrgPerson
sn: 測試
uid: 1
userPassword: b'1234'
]
最后,如果員工離職的話,公司內(nèi)所有賬號和權(quán)限應(yīng)該被回收,所以進行刪除操作:
#刪除用戶
c.delete(dn='cn=testuser1,cn=mygroup,dc=v3u,dc=cn')
print(c.result)
返回:
{'result': 0, 'description': 'success', 'dn': '', 'message': '', 'referrals': None, 'type': 'delResponse'}
再次查詢已經(jīng)獲取不到記錄:
print(c.search("dc=v3u,dc=cn", '(&(cn=testuser1))', attributes=['*']))
print(c.entries)
liuyue:mytornado liuyue$ python3 "/Users/liuyue/wodfan/work/mytornado/test_ldap.py"
False
[]
至此,我們就基于openldap的樹形結(jié)構(gòu)將組織以及用戶信息分別進行存儲和CURD(增刪改查)操作,在樹的root(根)一般定義總域(c=v3u)或者域名后綴(dc=cn),其次往往定義一個或多個組織(organization,o)或組織單元(organization unit,ou)。一個組織單元可以包含人員、設(shè)備信息(服務(wù)器、電腦等)相關(guān)信息。例如uid=testuser1,ou=v3u_users,dc=v3u,dc=cn,如圖所示:
除此以外,OpenLDAP 還是一種典型的分布式結(jié)構(gòu),提供復(fù)制同步,可將主服務(wù)器上的數(shù)據(jù)通過推或拉的機制實現(xiàn)在從服務(wù)器上更新,完成數(shù)據(jù)的同步,從而避免OpenLDAP 服務(wù)器出現(xiàn)單點故障,實現(xiàn)了高可用架構(gòu)。
OpenLdap目錄層級結(jié)構(gòu)是一個專門為搜索和瀏覽而設(shè)計的數(shù)據(jù)庫,雖然也支持簡單的插入、刪除、修改功能。但是我們可以理解為它是為瀏覽和搜索而生的,它的查詢速度很快,相反插入速度較慢,和關(guān)系型數(shù)據(jù)庫相比,它并不支持事務(wù)和回滾以及復(fù)雜的插入、更新等連貫操作功能,這一點和Elasticsearch有幾分相似,但是,古人云:“射不主皮,力不同科”,如果您的系統(tǒng)擴容頻繁,下游應(yīng)用層出不窮,那么您就可以考慮用它來做統(tǒng)一用戶管理,為您的應(yīng)用保駕護航。
原文轉(zhuǎn)載自「劉悅的技術(shù)博客」 https://v3u.cn/a_id_180