当前位置: 首页 > 后端技术 > Python

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

时间:2023-03-26 12:25:42 Python

,实际上是一个开源的应用协议,具有行业标准的特性,可以使用TCP协议为分布式信息提供访问控制和维护目录信息。这是传统意义上的书面解释,是的,毫无疑问,你会看得目瞪口呆。好吧,再感性一点,如果我每天早上刷推特,看看wang在吹什么,登录我的推特帐号和密码,然后我想去Instagram看看女神发了哪些新照片,好吗是的,登录Instagram账号和密码。摸鱼一上午,突然想起登录公司邮箱看看有没有新的需求。是的,又要那个该死的账号和密码,连查询社保、提取公积金、缴纳罚款都需要各自系统的账号和密码。想象一下,如果有一个系统可以统一管理和维护所有下游应用的账号和权限,我们就不需要再花时间为新的应用重复注册账号,而只需要关注应用本身,从而实现账户的集中认证管理。作为账户管理员,我们只需要维护OpenLDAP服务器条目,全球统一。这就是openladp能够给我们带来的好处。LDAP是一个非常典型的层次结构,信息模型是基于属性条目(entries)的。属性条目是属性的集合,具有全局唯一的“专有名称”DN,条目可以被DN引用。每个条目属性都有一个类型和一个或多个值。类型通常是易于记忆的名称,例如常用名称的“cn”或电子邮件地址的“mail”。条目值的语法取决于属性类型。例如,cn属性的值可能为“jackjoe”。邮件属性可能包含“admin@v3u.cn”。pngphoto属性可能包含PNG(二进制)格式的图像。这里简单介绍一下openldap中常用的分层关键字的解释:dc:DomainComponent域名范围,它的格式是把完整的域名分成几个部分,比如域名是v3u.cn,那么它写为dc=v3u,dc=cn。uid:UserId用户ID,如自增“1”。ou:OrganizationUnit组织单元,类似于文件系统中的子目录,是一个容器对象,一个组织单元可以包含其他各种对象(包括其他组织单元),比如“newgroup”。cn:CommonName通用名称,如“jackjoe”。sn:姓氏,如“joe”。dn:DistinguishedName唯一的识别名,类似于文件系统中的绝对路径,每个对象都有唯一的名字,类似于mysql的全局唯一索引,如"uid=tom,ou=market,dc=example,dc=com”,记住DN在目录树中始终是唯一的。理解了概念之后,我们来实践一下,因为实践永远是检验真理的唯一标准。首先,安装Docker。参考:win10系统下玩转DockerToolBox,更换国产镜像源(各种神坑)。然后拉取openldap镜像:dockerpullosixia/openldap:1.3.0这里我们使用1.3稳定版。拉取成功后,查看本地镜像dockerimages,可以看到只有200mb左右,很小:liuyue:~liuyue$dockerimagesREPOSITORYTAGIMAGEIDCREATEDSIZEosixia/openldap1.3.0faac9bb59f836monthsago260MB启动容器:dockerrun-p389:389--namemyopenldap--networkbridge--hostnameopenldap-host--envLDAP_ORGANISATION="v3u"--envLDAP_DOMAIN="v3u.cn"--envLDAP_ADMIN_PASSWORD="admin"--detachosixia/openldap:1.3.0这里我们使用端口映射到389端口作为链接桥,同时配置LDAP管理器:--envLDAP\_ORGANISATION="v3u",配置LDAP域:--envLDAP\_DOMAIN="v3u.cn",配置LDAP密码:--envLDAP\_ADMIN\_PASSWORD="admin",默认登录用户名:admin,开启后台守护进程。查看容器运行状态:dockerps可以看到已经在后台启动了:liuyue:~liuyue$dockerpsCONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMESb62d1f66c2b8osixia/openldap:1.3.0"/container/tool/run"2天前Up2天0.0.0.0:389->389/tcp,636/tcpmyopenldapliuyue:~liuyue$确认服务没有问题后,我们通过python写逻辑,先安装依赖pip3安装ldap3然后写测试脚本test\_ldap.py,先测试连接ldap服务器:fromldap3importServer,Connection,ALL,MODIFY_REPLACEs=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:mytornadoliuyue$python3"/Users/liuyue/wodfan/work/mytornado/test_ldap.py"dn:cn=admin,dc=v3u,dc=cnliuyue:mytornadoliuyue$在初始状态下,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:mytornadoliuyue$python3"/Users/liuyue/wodfan/work/mytornado/test_ldap.py"True{'result':0,'description':'success','dn':'','message':'','referrals':None,'type':'addResponse'}然后您可以向该组织添加一个组:#添加组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)returns:liuyue:mytornadoliuyue$python3"/Users/liuyue/wodfan/work/mytornado/test_ldap.py"{'result':0,'description':'success','dn':'','message':'','referrals':None,'type':'addResponse'}liuyue:mytornadoliuyue$接着添加人员:#adduserldap_attr={}ldap_attr['cn']="testuser1"ldap_attr['sn']="test"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是用户在系统中的唯一标识,注意指定刚刚创建的groupgroupmygroup,返回:liuyue:mytornadoliuyue$python3"/Users/liuyue/wodfan/work/mytornado/test_ldap.py"{'result':0,'description':'success','dn':'','message':'','referrals':None,'type':'addResponse'}liuyue:mytornadoliuyue$此时,我们可以查询新创建的用户:print(c.search("dc=v3u,dc=cn",'(&(cn=testuser1))',attributes=['*']))print(c.entries)查看用户的具体信息:liuyue:mytornadoliuyue$python3"/Users/liuyue/wodfan/work/mytornado/test_ldap.py"True[DN:cn=testuser1,cn=mygroup,dc=v3u,dc=cn-状态:已读-阅读时间:2020-11-23T17:58:08.569044cn:testuser1testuser1objectClass:inetOrgPersonsn:testuserPassword:b'1234']liuyue:mytornadoliuyue$如果我们nt修改用户信息,我们可以使用修改方法:#修改用户c.modify('cn=testuser1,cn=mygroup,dc=v3u,dc=cn',{'uid':[(MODIFY_REPLACE,['1'])]})print(c.result)在这里修改用户的uid属性,返回:liuyue:mytornadoliuyue$python3"/Users/liuyue/wodfan/work/mytornado/test_ldap.py"{'result':0,'description':'success','dn':'','message':'','referrals':None,'type':'modifyResponse'}liuyue:mytornadoliuyue$再次搜索用户:print(c.search("dc=v3u,dc=cn",'(&(cn=testuser1))',attributes=['*']))print(c.entries),可以看到添加了uid:liuyue:mytornadoliuyue$python3"/Users/liuyue/wodfan/work/mytornado/test_ldap.py"True[DN:cn=testuser1,cn=mygroup,dc=v3u,dc=cn-状态:读取-读取时间:2020-11-23T18:02:47.080555cn:testuser1testuser1objectClass:inetOrgPersonsn:testuid:1userPassword:b'1234']最后,如果员工离职,公司所有账号和权限都要回收,所以删除用户:#deleteuserc.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.词条)liuyue:mytornadoliuyue$python3"/Users/liuyue/wodfan/work/mytornado/test_ldap.py"False[]至此,我们基于openldap的树结构,分别存储组织和用户信息,并进行CURD(增删改查)、修改和查询)操作。在树的根部(root)一般定义总域(c=v3u)或域名后缀(dc=cn),然后往往定义一个或多个组织(organization,o)或组织单位(organizationunit,ou)一个组织单元可以包含人员、设备信息(服务器、计算机等)的相关信息。比如uid=testuser1,ou=v3u\_users,dc=v3u,dc=cn,如图:另外OpenLDAP也是典型的分布式结构,提供复制同步,主服务器上的数据可以通过push或pull机制在从服务器上实现更新,完成数据同步,从而避免OpenLDAP服务器上的单点故障,实现高可用架构。OpenLdap目录层次结构是专门为搜索和浏览而设计的数据库,尽管它也支持简单的插入、删除和修改功能。但是我们可以理解为它是为浏览和搜索而生的。它的查询速度很快,但是插入速度比较慢。与关系型数据库相比,它不支持事务和回滚,以及复杂的插入、更新等,连贯的操作功能有点类似于Elasticsearch。然而,古人云:“不能射皮,则不可为也”。如果你的系统经常扩容,下游应用层出不穷,那你可以考虑用它来统一用户管理,保护你的应用。原文转载自《刘越的技术博客》https://v3u.cn/a_id_180