金甌無缺江河一統(tǒng)|Win10系統(tǒng)基于Docker和Python3搭建并維護統(tǒng)一認(rèn)證系統(tǒng)OpenLdap

原文轉(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,如圖所示:

image

除此以外,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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容