文档章节

使用包ldap3进行Python的LDAP操作

shawnplaying
 shawnplaying
发布于 2016/08/16 13:22
字数 1874
阅读 4034
收藏 1

背景:我的管理平台系统需要在权限验证方面与ldap集成,所以需要使用python操作LDAP。

本来想使用python-ldap,但是安装过程中出现如下问题,而且花费很多时间精力没有解决该问题,所以放弃python-ldap,而使用ldap3。

E:\>pip install python-ldap
Collecting python-ldap
D:\app\Python27\lib\site-packages\pip\_vendor\requests\packages\urllib3\util\ssl_.py:318: SNIMissingWarning: An HTTPS re
quest has been made, but the SNI (Subject Name Indication) extension to TLS is not available on this platform. This may
cause the server to present an incorrect TLS certificate, which can cause validation failures. You can upgrade to a newe
r version of Python to solve this. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#sni
missingwarning.
  SNIMissingWarning

省略。。。
    C:\Users\zhaoxp2\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\VC\Bin\amd64\cl.exe /c /nologo /O
x /MD /W3 /GS- /DNDEBUG -DHAVE_SASL -DHAVE_TLS -DHAVE_LIBLDAP_R -DHAVE_LIBLDAP_R -DLDAPMODULE_VERSION=2.4.27 -IModules -
I/usr/include -I/usr/include/sasl -I/usr/local/include -I/usr/local/include/sasl -ID:\app\Python27\include -ID:\app\Pyth
on27\PC /TcModules/LDAPObject.c /Fobuild\temp.win-amd64-2.7\Release\Modules/LDAPObject.obj
    LDAPObject.c
    c:\users\zhaoxp2\appdata\local\temp\pip-build-kecixv\python-ldap\modules\errors.h(8) : fatal error C1083: Cannot ope
n include file: 'lber.h': No such file or directory
    error: command 'C:\\Users\\zhaoxp2\\AppData\\Local\\Programs\\Common\\Microsoft\\Visual C++ for Python\\9.0\\VC\\Bin
\\amd64\\cl.exe' failed with exit status 2

    ----------------------------------------
Command "D:\app\Python27\python.exe -u -c "import setuptools, tokenize;__file__='c:\\users\\zhaoxp2\\appdata\\local\\tem
p\\pip-build-kecixv\\python-ldap\\setup.py';exec(compile(getattr(tokenize, 'open', open)(__file__).read().replace('\r\n'
, '\n'), __file__, 'exec'))" install --record c:\users\zhaoxp2\appdata\local\temp\pip-f4qvel-record\install-record.txt -
-single-version-externally-managed --compile" failed with error code 1 in c:\users\zhaoxp2\appdata\local\temp\pip-build-
kecixv\python-ldap\

安装ldap3

安装ldap3很简单,pip install ldap3即可。地址:https://pypi.python.org/pypi/ldap3

为什么使用ldap3?下面是给出的原因:

A strictly RFC 4510 conforming LDAP V3 pure Python client library. The same codebase works with Python 2, Python 3, PyPy, PyPy3 and Nuikta.

使用ldap3访问LDAP服务器

接下来是ldap3的使用介绍。

参考:http://ldap3.readthedocs.io/tutorial.html

3种连接方法:

1 anonymous

2 simple password

3 SASL(simple authentication and security layer)

这里注意文档中说明了longin就是bind(后面代码中会有相关参数)。

在API的Connection中定义了5中策略:

  策略 同步否? Return
1 SYNC synchronous True/False
2 ASYNC asynchronous Integer
3 LDIF    
4 RESTARTABLE synchronous True/False
5 REUSABLE asynchronous Integer

在异步模式下,将返回message_id而不是True或者False。另外异步模式下将会调用Connection的get_response(message_id)方法。还可以设置timeout参数。

LDIF模式用来创建LDIF-CHANGEs流。The LDIF strategy is used to create a stream of LDIF-CHANGEs.

默认模式是SYNC。

连接:

>>> server = Server('ipa.demo1.freeipa.org')
>>> conn = Connection(server)
>>> conn.bind()
True

或者

>> conn = Connection('ipa.demo1.freeipa.org', auto_bind=True)
True

查看连接信息:

print server
print conn

获取服务器信息:

>>> server = Server('ipa.demo1.freeipa.org', get_info=ALL)
>>> conn = Connection(server, auto_bind=True)
>>> server.info
DSA info (from DSE):
  Supported LDAP Versions: 2, 3
  Naming Contexts:
    cn=changelog
省略

>>> server.schema
DSA Schema from: cn=schema
  Attribute types:{'ipaNTTrustForestTrustInfo': Attribute type: 2.16.840.1.113730.3.8.11.17
  Short name: ipaNTTrustForestTrustInfo
  Description: Forest trust information for a trusted domain object
省略

登录:

>>> # import class and constants
>>> from ldap3 import Server, Connection, ALL, NTLM

>>> # define the server and the connection
>>> server = Server('10.99.201.86', get_info=ALL)
>>> conn = Connection(server, user="Domain\\User", password="password", authentication=“NTLM”)

查看登录信息:

>>> conn.extend.standard.who_am_i()

如果是匿名登录那么返回空。

所以使用用户名密码登录:

>>> conn = Connection(server, 'uid=admin, cn=users, cn=accounts, dc=demo1, dc=freeipa, dc=org', 'Secret123', auto_bind=True)
>>> conn.extend.standard.who_am_i()
'dn: uid=admin,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org'

使用安全方式登录,两种:LDAP over TLS or the StartTLS extended operation。这里不做详细说明,具体参考官方文档。下面只列出相关代码:

>>> server = Server('ipa.demo1.freeipa.org', use_ssl=True, get_info=ALL)
>>> conn = Connection(server, 'uid=admin, cn=users, cn=accounts, dc=demo1, dc=freeipa, dc=org', 'Secret123', auto_bind=True)
>>> print(conn)
ldaps://ipa.demo1.freeipa.org:636 - ssl - user: uid=admin, cn=users, cn=accounts, dc=demo1, dc=freeipa, dc=org - bound - open - <local: 192.168.1.101:51438 - remote: 209.132.178.99:636> - tls not started - listening - SyncStrategy - internal decoder
>>> from ldap3 import Server, Connection, Tls
>>> import ssl
>>> tls_configuration = Tls(validate=ssl.CERT_REQUIRED, version=ssl.PROTOCOL_TLSv1)
>>> server = Server('ipa.demo1.freeipa.org', use_ssl=True, tls=tls_configuration)
>>> conn = Connection(server)
>>> conn.open()
...
ldap3.core.exceptions.LDAPSocketOpenError: (LDAPSocketOpenError('socket ssl wrapping error: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:600)',),)

访问数据

这里介绍同步和异步两种方式。读文档说明,异步是使用独立线程完成操作的。同步的就是发送消息然后等待接受消息。

异步经常用于event-driven,事件驱动。

另外还有一种Compare操作。它既是用来验证一个attribute是否有一个value。这个操作可以用来做密码验证(不用bind操作)。

任何同步操作后Connection对象中都会有一些attribute被populated。

  • result: the result of the last operation (as returned by the server)
  • response: the entries found (if the last operation is a Search)
  • entries: the entries found exposed via the abstraction layer (if the last operation is a Search)
  • last_error: the error occurred in the last operation, if any
  • bound: True if the connection is bound to the server
  • listening: True if the socket is listening to the server
  • closed: True if the socket is not open

搜索操作

搜索操作需要三个参数,但是只有两个是必须:

  • search_base: the location in the DIT where the search will start
  • search_filter: what are you searching

 这里的search_filter有特殊的语法。它是基于assertion,而assertion是一个bracketed expression。assertion是true false或者undefined(等同于false)。assertion使用& | ! 组织,可以包含 = <= >= =* ~=等。另外注意,这里没有 < 和 > 符号。

例如:

(&
    (|
        (givenName=Fred)
        (givenName=John)
    )
    (mail=*@example.org)
)

代码示例:

搜索所有person,即objectclass=persono。

>>> from ldap3 import Server, Connection, ALL
>>> server = Server('ipa.demo1.freeipa.org', get_info=ALL)
>>> conn = Connection(server, 'uid=admin, cn=users, cn=accounts, dc=demo1, dc=freeipa, dc=org', 'Secret123', auto_bind=True)
>>> conn.search('dc=demo1, dc=freeipa, dc=org', '(objectclass=person)')
True
>>> conn.entries
[DN: uid=admin,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org
, DN: uid=manager,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org
, DN: uid=employee,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org
, DN: uid=helpdesk,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org
]

请求获取部分属性。

>>> conn.search('dc=demo1, dc=freeipa, dc=org', '(&(objectclass=person)(uid=admin))', attributes=['sn','krbLastPwdChange', 'objectclass'])
True
>>> conn.entries[0]
DN: uid=admin,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org
    krbLastPwdChange: 2015-09-30 04:06:59+00:00
    objectclass: top
                 person
                 posixaccount
                 krbprincipalaux
                 krbticketpolicyaux
                 inetuser
                 ipaobject
                 ipasshuser
                 ipaSshGroupOfPubKeys
    sn: Administrator

属性获取方法:

>>> entry = entries[0]
>>> entry.krbLastPwdChange
krbLastPwdChange: 2015-09-30 04:06:59+00:00
>>> entry.KRBLastPwdCHANGE
krbLastPwdChange: 2015-09-30 04:06:59+00:00
>>> entry['krbLastPwdChange']
krbLastPwdChange: 2015-09-30 04:06:59+00:00
>>> entry['KRB LAST PWD CHANGE']
krbLastPwdChange: 2015-09-30 04:06:59+00:00

>>> entry.krbLastPwdChange.values
[datetime.datetime(2015, 9, 30, 4, 6, 59, tzinfo=OffsetTzInfo(offset=0, name='UTC'))]
>>> entry.krbLastPwdChange.raw_values
[b'20150930040659Z']

一点要注意,那就是search_scope表示了搜索范围,有三种。默认SUBTREE。

1 BASE A base search limits the search to the base object 一般用来检查object的存在与否。
2 LEVEL A one-level search is restricted to the immediate children of a base object, but excludes the base object itself. 
3 SUBTREE A subtree search (or a deep search) includes all child objects as well as the base object. 

 

关于LDIF:

>>> print(conn.entries[0].entry_to_ldif())
version: 1
dn: uid=admin,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org
objectclass: top
objectclass: person
objectclass: posixaccount
objectclass: krbprincipalaux
objectclass: krbticketpolicyaux
objectclass: inetuser
objectclass: ipaobject
objectclass: ipasshuser
objectclass: ipaSshGroupOfPubKeys
krbLastPwdChange: 20150930040659Z
sn: Administrator
# total number of entries: 1

或者使用JSON表示:

>>> print(entry.entry_to_json())
{
    "attributes": {
        "krbLastPwdChange": [
            "2015-09-30 04:06:59+00:00"
        ],
        "objectclass": [
            "top",
            "person",
            "posixaccount",
            "krbprincipalaux",
            "krbticketpolicyaux",
            "inetuser",
            "ipaobject",
            "ipasshuser",
            "ipaSshGroupOfPubKeys"
        ],
        "sn": [
            "Administrator"
        ]
    },
    "dn": "uid=admin,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org"

另外关于binary values:

>>> from ldap3.utils.conv import escape_bytes
>>> unique_id = b'\xca@\xf2k\x1d\x86\xcaL\xb7\xa2\xca@\xf2k\x1d\x86'
>>> search_filter = '(nsUniqueID=' + escape_bytes(unique_id) + ')'
>>> conn.search('dc=demo1, dc=freeipa, dc=org', search_filter, attributes=['nsUniqueId'])

关于connection context manager:

>>> with Connection(server, 'uid=admin, cn=users, cn=accounts, dc=demo1, dc=freeipa, dc=org', 'Secret123') as conn:
        conn.search('dc=demo1, dc=freeipa, dc=org', '(&(objectclass=person)(uid=admin))', attributes=['sn','krbLastPwdChange', 'objectclass'])
        entry = conn.entries[0]
True
>>> conn.bound
False
>>> entry
DN: uid=admin,cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org
krbLastPwdChange: 2015-09-30 04:06:59+00:00
objectclass: top
             person
             posixaccount
             krbprincipalaux
             krbticketpolicyaux
             inetuser
             ipaobject
             ipasshuser
             ipaSshGroupOfPubKeys
sn: Administrator

增加操作

>>> # Create a container for our new entries
>>> conn.add('ou=ldap3-tutorial, dc=demo1, dc=freeipa, dc=org', 'organizationalUnit')
>>> True
>>> # Add some users
>>> conn.add('cn=b.young,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', 'inetorgperson', {'givenName': 'Beatrix', 'sn': 'Young', 'departmentNumber':'DEV', 'telephoneNumber': 1111})
>>> True
>>> conn.add('cn=j.smith,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', 'inetorgperson', {'givenName': 'John', 'sn': 'Smith', 'departmentNumber':'DEV',  'telephoneNumber': 2222})
>>> True
>>> conn.add('cn=m.smith,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', 'inetorgperson', {'givenName': 'Marianne', 'sn': 'Smith', 'departmentNumber':'QA',  'telephoneNumber': 3333})
>>> True
>>> conn.add('cn=quentin.cat,ou=ldap3-tutorial,dc=demo1,dc=freeipa,dc=org', 'inetorgperson', {'givenName': 'Quentin', 'sn': 'Cat', 'departmentNumber':'CC',  'telephoneNumber': 4444})

 

© 著作权归作者所有

共有 人打赏支持
shawnplaying
粉丝 14
博文 128
码字总数 70642
作品 0
海淀
系统管理员
加载中

评论(1)

abelhu
abelhu
博主,我想问下,你在连接的时候用普通用户可以登录吗,我按照你的做的,管理员可以登录,但是普通用户就不可以,你之前与大奥过吗
jumpserver 3.0 开源跳板机环境搭建

摘要: Jumpserver 是一款由python编写开源的跳板机(堡垒机)系统,实现了跳板机应有的功能。基于ssh协议来管理,客户端无需安装agent。 特点: 完全开源,GPL授权 Python编写,容易再次开发 ...

YU文武貝
07/14
0
0
Review board整合ldap

Review board整合ldap Review board本身已经支持ldap登录,我们需要做的就是一些安装、配置工作。首先review board需要python-ldap,如果没有安装,我们在打开ldap配置页面,就会提醒LDAP au...

youthflies
2014/07/15
0
0
在Windows安装Python的教程

在Windows安装Python的教程 作者:马哥教育 来源:http://www.magedu.com/74574.html Python几乎可以在任何平台下运行,如我们所熟悉的:Windows/Unix/Linux/Macintosh。 在这里我们说一下,...

Py爱好
07/26
0
0
pycharm中使用anaconda

source activate python34 # for Linux & Mac# 激活后,会发现terminal输入的地方多了python34的字样,实际上,此时系统做的事情就是把默认2.7环境从PATH中去除,再把3.4对应的命令加入PATH#...

h8b6pk7m7r8
01/07
0
0
用了这个几个Python内置小工具,可以让你的工作效率提升一倍

我们将会介绍4个Python解释器自身提供的小工具。 这些小工具在笔者的日常工作中经常用到, 减少了各种时间的浪费, 然而,却很容易被大家忽略。 每当有新来的同事看到我这么使用时, 都忍不住...

Python新世界
07/24
0
0

没有更多内容

加载失败,请刷新页面

加载更多

区块链教程以太坊源码分析chain-indexer区块链索引一

兄弟连区块链教程以太坊源码分析chain-indexer区块链索引一 chain_indexer 区块链索引 chain_indexer.go 源码解析 chain_indexer 顾名思义, 就是用来给区块链创建索引的功能。 之前在eth协议...

兄弟连区块链入门教程
6分钟前
0
0
社会化分享插件集成分享

一.前提摘要 社会化分享每个app必备的推广需求,无论是拉新,邀请,游戏奖励,等等都离不开分享的影子,下面我们介绍下社会化分享的插件; 首先要说下,现在的社交App,社区App等,国内外的...

佳妮
6分钟前
0
0
IOC 之 Spring 统一资源加载策略

统一资源:Resource org.springframework.core.io.Resource 为 Spring 框架所有资源的抽象和访问接口 它继承 org.springframework.core.io.InputStreamSource接口 作为所有资源的统一抽象,S...

职业搬砖20年
6分钟前
0
0
Python爬虫实战入门一:工具准备

一、基础知识 使用Python编写爬虫,当然至少得了解Python基本的语法,了解: 基本数据结构 数据类型 控制流 函数的使用 模块的使用 不需要过多过深的Python知识,仅此而已。 个人推荐《Pytho...

糖宝lsh
10分钟前
0
0
Hanlp中使用纯JAVA实现CRF分词

Hanlp中使用纯JAVA实现CRF分词 与基于隐马尔可夫模型的最短路径分词、N-最短路径分词相比,基于条件随机场(CRF)的分词对未登录词有更好的支持。本文(HanLP)使用纯Java实现CRF模型的读取与...

左手的倒影
12分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部