金瓯无缺江河一统|Win10系统基于Docker和Python3搭建并维护统一认证系统OpenLdap

原文转载自「刘悦的技术博客」https://v3u.cn/a_id_180

OpenLdap(Lightweight Directory Access Protocol)是什么?它其实是一个开源的、具备工业标准特性的应用协议,可以使用TCP协议提供访问控制和维护分布式信息的目录信息。这是一个传统意义上的书面解释,是的,毫无疑问,你会一脸懵逼。好吧,让我们变得感性一点,假如我每天早上使用Twitter想听听懂王又吹了什么牛,登录Twitter账号密码,紧接着又想上Instagram看看女神又post了什么新靓照,好的,登录Instagram账号密码,摸了一上午的鱼之后,突然想起来要登录公司的邮箱,看看有没有新需求,是的,又需要那该死的账号和密码,甚至于查询社保、公积金提取、交罚款都需要各自系统的账号和密码。想象一下,如果有一套系统可以统一管理和维护所有下游应用的账号和权限,我们不需要花时间重复的注册新应用的账号,而只需要关注应用本身,从而实现账号集中认证管理,此时作为账号管理员的我们只须维护OpenLDAP 服务器条目即可,金瓯无缺江山一统,这就是openladp能够带给我们的好处。

LDAP是非常典型的层级结构,信息模型是建立在属性条目(entries)的基础上。一个属性条目是一些属性的集合,并且具有一个全局唯一的"可区分名称"DN,一个条目可以通过DN来引用。每一个条目的属性具有一个类型和一个或者多个值。类型通常是容易记忆的名称,比如"cn"是通用名称(common name) ,或者"mail"是电子邮件地址。条目的值的语法取决于属性类型。比如,cn属性可能具有一个值"jack joe" 。一个mail属性可能包含"admin@v3u.cn" 。一个pngphoto属性可能包含一幅PNG(二进制)格式的图片。

这里简单介绍一下openldap常用的层级关键字的解释:

dc:Domain Component 域名的范围,其格式是将完整的域名分成几部分,如域名为v3u.cn则写成dc=v3u,dc=cn。

uid:User Id 用户ID,比如自增长“1”。

ou:Organization Unit 组织单位,类似于文件系统中的子目录,它是一个容器对象,组织单位可以包含其他各种对象(包括其他组织单元),如“newgroup”。
cn:Common Name 公共名称,如“jack joe”。
sn: Surname 姓,如“joe”。
dn :Distinguished Name 惟一辨别名,类似于文件系统中的绝对路径,每个对象都有一个惟一的名称,类似于mysql的全局唯一索引,如“uid= tom,ou=market,dc=example,dc=com”,记住在一个目录树中DN总是惟一的。

理解了概念,让我们来实操一把,因为实践永远是检验真理的唯一标准,首先安装Docker,参照:win10系统下把玩折腾DockerToolBox以及更换国内镜像源(各种神坑)

随后拉取openldap镜像:

docker pull osixia/openldap:1.3.0

这里我们使用1.3稳定版,拉取成功后查看本地镜像

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",默认登录用户名:admin,并且开启后台守护进程。

查看容器运行状态:

docker ps

可以看到已经在后台启动了:

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$

服务确认没问题之后,我们通过python来进行逻辑的编写,首先安装依赖

pip3 install ldap3

随后编写测试脚本 test_ldap.py ,首先测试一下链接ldap服务器:

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)不要写错,不出意外的话,系统会返回当前验证的用户信息:

liuyue:mytornado liuyue$ python3 "/Users/liuyue/wodfan/work/mytornado/test_ldap.py"  
dn:cn=admin,dc=v3u,dc=cn  
liuyue:mytornado liuyue$

初始状态下,LDAP是一个空目录,即没有任何数据。可通过程序代码向目录数据库中添加数据,也可使用ldap3库的ldapadd命令来完成添加数据的操作,该命令可将一个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则是该用户在系统中的唯一标识,注意指定刚刚建立的群组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已经被添加好了:

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'  
]

最后,如果员工离职的话,公司内所有账号和权限应该被回收,所以进行删除操作:

#删除用户  
c.delete(dn='cn=testuser1,cn=mygroup,dc=v3u,dc=cn')  
print(c.result)

返回:

{'result': 0, 'description': 'success', 'dn': '', 'message': '', 'referrals': None, 'type': 'delResponse'}

再次查询已经获取不到记录:

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的树形结构将组织以及用户信息分别进行存储和CURD(增删改查)操作,在树的root(根)一般定义总域(c=v3u)或者域名后缀(dc=cn),其次往往定义一个或多个组织(organization,o)或组织单元(organization unit,ou)。一个组织单元可以包含人员、设备信息(服务器、电脑等)相关信息。例如uid=testuser1,ou=v3u_users,dc=v3u,dc=cn,如图所示:

image

除此以外,OpenLDAP 还是一种典型的分布式结构,提供复制同步,可将主服务器上的数据通过推或拉的机制实现在从服务器上更新,完成数据的同步,从而避免OpenLDAP 服务器出现单点故障,实现了高可用架构。

OpenLdap目录层级结构是一个专门为搜索和浏览而设计的数据库,虽然也支持简单的插入、删除、修改功能。但是我们可以理解为它是为浏览和搜索而生的,它的查询速度很快,相反插入速度较慢,和关系型数据库相比,它并不支持事务和回滚以及复杂的插入、更新等连贯操作功能,这一点和Elasticsearch有几分相似,但是,古人云:“射不主皮,力不同科”,如果您的系统扩容频繁,下游应用层出不穷,那么您就可以考虑用它来做统一用户管理,为您的应用保驾护航。

原文转载自「刘悦的技术博客」 https://v3u.cn/a_id_180

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,384评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,845评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,148评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,640评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,731评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,712评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,703评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,473评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,915评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,227评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,384评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,063评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,706评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,302评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,531评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,321评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,248评论 2 352

推荐阅读更多精彩内容