原文转载自「刘悦的技术博客」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,如图所示:

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

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

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

金瓯无缺江河一统|Win10系统基于Docker和Python3搭建并维护统一认证系统OpenLdap的更多相关文章

  1. #研发解决方案介绍#IdCenter(内部统一认证系统)

    郑昀 基于朱传志的设计文档 最后更新于2014/11/13 关键词:LDAP.认证.权限分配.IdCenter. 本文档适用人员:研发   曾经一个IT内部系统配一套帐号体系和授权   线上生产环境里 ...

  2. 云方案,依托H3C彩虹云存储架构,结合UIA统一认证系统,实现了用户数据的集中存储和管理

    客户的声音 资料云项目在迷你云基础上二次开发,通过使用云存储技术及文件秒传技术,对文件进行统一存储与管理,以达到节约文件管理成本.存储成本目的:通过有效的文件版本控制机制,以达到风险管控的目的:通过多 ...

  3. 基于Docker的服务器搭建

    -----------基于Docker的多种服务器搭建----------- 开发环境 本机上的虚拟机 Centos7.4 Docker1.13.1 Openssl1.1.1 1 Nginx 1.1 ...

  4. 基于docker+reveal.js搭建一个属于自己的在线ppt网站

    前言 最近热衷于Docker,由于这段时间使用Docker来折腾自己的服务器,越来越感觉这是一种及其被应该推广的技术,因此想在公司内部也做一次技术分享.当然,如果只是做的PPT,我就不写这文章了.既然 ...

  5. 基于Docker+Jenkins+Gitlab搭建持续集成环境

    随着DevOps理念和敏捷理念的发展,我们希望通过自动化技术,加快项目的迭代.尤其是当使用微服务方案后,面临在大量的项目构建和部署工作,借助于jenkins的持续集成,可以快速把应用打包成docker ...

  6. 基于docker环境,搭建 jetty环境, 部署java项目

    前提: 1.Ubuntu 系统. 2.docker环境已经安装好. 实现步骤: 1.上docker hub 下载jetty docker 镜像. 执行命令:$ sudo docker pull jet ...

  7. 基于Docker的GitLab搭建

    今天写一些Docker搭建GitLab,好久没有写博客园了,今天又回来了,为了学习技术? 建议使用Linux内核系统,或者虚拟机,首先安装docker环境(菜鸟教程) 一.下载镜像文件 如果慢的话,可 ...

  8. 基于Docker和Golang搭建Web服务器

    1 场景描述 基于centos7的docker镜像搭建golang开发环境 在docker容器内,使用golang实现一个Web服务器 启动docker容器,并在容器内启动Web服务器 我购买了一个最 ...

  9. 【分布式】-- 基于Nacos、OpenFeign搭建的微服务抽奖系统后台小案例

    1.项目介绍 最近入项目之前要求熟悉一下SpringCloud Nacos微服务基于Feign接口调用并整合Swagger2进行接口文档展示给前端,所以自己按照要求来编写并整合了一套基于SpringC ...

随机推荐

  1. 百万数据 mysql count(*)优化

    一.故事背景有一张 500w 左右的表做 select count(*) 速度特别慢. 二.原 SQL 分析Server version: 5.7.24-log MySQL Community Ser ...

  2. 精彩分享 | 欢乐游戏 Istio 云原生服务网格三年实践思考

    作者 吴连火,腾讯游戏专家开发工程师,负责欢乐游戏大规模分布式服务器架构.有十余年微服务架构经验,擅长分布式系统领域,有丰富的高性能高可用实践经验,目前正带领团队完成云原生技术栈的全面转型. 导语 欢 ...

  3. 面试突击55:delete、drop、truncate有什么区别?

    在 MySQL 中,删除的方法总共有 3 种:delete.truncate.drop,而三者的用法和使用场景又完全不同,接下来我们具体来看. 1.delete detele 可用于删除表的部分或所有 ...

  4. FlinkSQL源码阅读-schema管理

    在Flink SQL中, 元数据的管理分为三层: catalog-> database-> table, 我们知道Flink SQL是依托calcite框架来进行SQL执行树生产,校验,优 ...

  5. 【Golang】创建有配置参数的结构体时,可选参数应该怎么传?

    写在前面的话 Golang中构建结构体的时候,需要通过可选参数方式创建,我们怎么样设计一个灵活的API来初始化结构体呢. 让我们通过如下的代码片段,一步一步说明基于可选参数模式的灵活 API 怎么设计 ...

  6. 使用PowerShell下载文件

    更新记录 本文迁移自Panda666原博客,原发布时间:2021年7月12日. 使用Invoke-WebRequest指令下载文件 [Net.ServicePointManager]::Securit ...

  7. C语言学习之我见-strcat()字符拼接函数(有缺陷)

    strcat()函数,用于两个字符串的拼接. (1)函数原型: char * strcat(char *Dest,const char * Source); (2)头文件: #include < ...

  8. 雪花算法及微服务集群唯一ID解决方案

    雪花算法(SnowFlake) 简介 现在的服务基本是分布式.微服务形式的,而且大数据量也导致分库分表的产生,对于水平分表就需要保证表中 id 的全局唯一性. 对于 MySQL 而言,一个表中的主键 ...

  9. 【python基础】第11回 数据类型内置方法 02

    本章内容概要 列表内置方法 字典内置方法 元组内置方法 集合内置方法 可变类型与不可变类型 本章内容详细 1.列表内置方法 list 列表在调用内置方法之后不会产生新的值 1.1 统计列表中的数据值的 ...

  10. 梯度下降算法实现原理(Gradient Descent)

    概述   梯度下降法(Gradient Descent)是一个算法,但不是像多元线性回归那样是一个具体做回归任务的算法,而是一个非常通用的优化算法来帮助一些机器学习算法求解出最优解的,所谓的通用就是很 ...