HOW-TO:使用 python-ldap 进行 LDAP 绑定+身份验证
HOW-TO: LDAP bind+authenticate using python-ldap
能否请您告知如何解决以下尝试;
我试图绑定到 ldap 服务器,但没有成功,
当我做
openssl s_client -CApath /etc/pki/ca-trust/source/anchors/ -connect ...:636
成功:
Verify return code: 0 (ok)
那是来自系统端,但是当我尝试通过 python-ldap 模块进行绑定时:
In [1]: import ldap
In [2]: l = ldap.initialize('ldaps://...:636')
In [3]: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT,ldap.OPT_X_TLS_ALLOW)
In [4]: l.set_option(ldap.OPT_X_TLS_CACERTFILE,"/etc/pki/ca-trust/source/anchors/cacert.pem")
In [5]: l.set_option(ldap.OPT_X_TLS_NEWCTX,0)
In [6]: l.simple_bind_s("...", "...")
---------------------------------------------------------------------------
SERVER_DOWN Traceback (most recent call last)
<ipython-input-6-a59dae8ba541> in <module>()
----> 1 l.simple_bind_s("...", "...")
/usr/lib64/python2.7/site-packages/ldap/ldapobject.pyc in simple_bind_s(self, who, cred, serverctrls, clientctrls)
205 simple_bind_s([who='' [,cred='']]) -> None
206 """
--> 207 msgid = self.simple_bind(who,cred,serverctrls,clientctrls)
208 resp_type, resp_data, resp_msgid, resp_ctrls = self.result3(msgid,all=1,timeout=self.timeout)
209 return resp_type, resp_data, resp_msgid, resp_ctrls
/usr/lib64/python2.7/site-packages/ldap/ldapobject.pyc in simple_bind(self, who, cred, serverctrls, clientctrls)
199 simple_bind([who='' [,cred='']]) -> int
200 """
--> 201 return self._ldap_call(self._l.simple_bind,who,cred,RequestControlTuples(serverctrls),RequestControlTuples(clientctrls))
202
203 def simple_bind_s(self,who='',cred='',serverctrls=None,clientctrls=None):
/usr/lib64/python2.7/site-packages/ldap/ldapobject.pyc in _ldap_call(self, func, *args, **kwargs)
97 try:
98 try:
---> 99 result = func(*args,**kwargs)
100 if __debug__ and self._trace_level>=2:
101 if func.__name__!="unbind_ext":
SERVER_DOWN: {'info': 'TLS error -8157:Certificate extension not found.', 'desc': "Can't contact LDAP server"}
In [1]: import ldap
In [2]: l = ldap.initialize('ldaps://...:636')
In [3]: l.set_option(ldap.OPT_X_TLS_REQUIRE_CERT,ldap.OPT_X_TLS_ALLOW)
In [4]: l.set_option(ldap.OPT_X_TLS_CACERTFILE,"/etc/pki/ca-trust/source/anchors/cacert.pem")
In [5]: l.protocol_version = ldap.VERSION3
In [6]: l.set_option(ldap.OPT_REFERRALS, 0)
In [7]: l.simple_bind_s("...", "...")
---------------------------------------------------------------------------
SERVER_DOWN Traceback (most recent call last)
<ipython-input-7-a59dae8ba541> in <module>()
----> 1 l.simple_bind_s("...", "...")
/usr/lib64/python2.7/site-packages/ldap/ldapobject.pyc in simple_bind_s(self, who, cred, serverctrls, clientctrls)
205 simple_bind_s([who='' [,cred='']]) -> None
206 """
--> 207 msgid = self.simple_bind(who,cred,serverctrls,clientctrls)
208 resp_type, resp_data, resp_msgid, resp_ctrls = self.result3(msgid,all=1,timeout=self.timeout)
209 return resp_type, resp_data, resp_msgid, resp_ctrls
/usr/lib64/python2.7/site-packages/ldap/ldapobject.pyc in simple_bind(self, who, cred, serverctrls, clientctrls)
199 simple_bind([who='' [,cred='']]) -> int
200 """
--> 201 return self._ldap_call(self._l.simple_bind,who,cred,RequestControlTuples(serverctrls),RequestControlTuples(clientctrls))
202
203 def simple_bind_s(self,who='',cred='',serverctrls=None,clientctrls=None):
/usr/lib64/python2.7/site-packages/ldap/ldapobject.pyc in _ldap_call(self, func, *args, **kwargs)
97 try:
98 try:
---> 99 result = func(*args,**kwargs)
100 if __debug__ and self._trace_level>=2:
101 if func.__name__!="unbind_ext":
SERVER_DOWN: {'info': "TLS error -8172:Peer's certificate issuer has been marked as not trusted by the user.", 'desc': "Can't contact LDAP server"}
import ldap
import os
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
l = ldap.initialize('ldaps://x.x.x.x:636')
l.set_option(ldap.OPT_REFERRALS, 0)
l.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
l.set_option(ldap.OPT_X_TLS_CACERTFILE, os.getcwd()+"/cacert.pem")
l.set_option(ldap.OPT_X_TLS,ldap.OPT_X_TLS_DEMAND)
l.set_option(ldap.OPT_X_TLS_DEMAND, True)
l.set_option(ldap.OPT_DEBUG_LEVEL, 255)
#l.start_tls_s()
在我的机器上,python 2.6;我发现 /etc/openldap/ldap.conf
被使用并优先于一些选项,即使它们设置为 ldap.set_option(..., ...)
.
根据您的发行版,它可能希望证书位于 /etc/openldap/cacerts
而不是 /etc/openldap/certs
这是我调试此类问题的方法。
1。在系统范围内安装证书 (openldap)
cp mycert.pem /etc/openldap/certs
cacertdir_rehash /etc/openldap/certs
2。在系统范围内安装根证书(可选)
如果您将同一个根证书用于其他用途,您可能需要:
update-ca-trust enable
cp mycert.pem /etc/pki/ca-trust/source/anchors/
update-ca-trust extract
update-ca-trust check
3。编辑 /etc/openldap/ldap.conf
编辑配置文件:
# /etc/openldap/ldap.conf
base dc=example,dc=com
uri ldaps://ldap.example.com:636/
ssl yes
tls_cacertdir /etc/openldap/certs
pam_password md5
当 ldapsearch
正常工作时停止。
4。编写测试脚本
例如test_ldap.py
#!/usr/bin/env python
import ldap, sys
LDAP_SERVER = 'ldaps://ldap.example.com:636'
LDAP_BASE = 'dc=example,dc=com'
try:
conn = ldap.initialize(LDAP_SERVER)
except ldap.LDAPError, e:
sys.stderr.write("Fatal Error.n")
raise
# this may or may not raise an error, e.g. TLS error -8172
items = conn.search_s(LDAP_BASE, ldap.SCOPE_SUBTREE, attrlist=['dn'])
5。使用 strace
如果上述步骤失败,您可以使用strace查看具体情况,例如
strace -e open test_ldap.py
能否请您告知如何解决以下尝试; 我试图绑定到 ldap 服务器,但没有成功, 当我做
openssl s_client -CApath /etc/pki/ca-trust/source/anchors/ -connect ...:636
成功:
Verify return code: 0 (ok)
那是来自系统端,但是当我尝试通过 python-ldap 模块进行绑定时:
In [1]: import ldap
In [2]: l = ldap.initialize('ldaps://...:636')
In [3]: ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT,ldap.OPT_X_TLS_ALLOW)
In [4]: l.set_option(ldap.OPT_X_TLS_CACERTFILE,"/etc/pki/ca-trust/source/anchors/cacert.pem")
In [5]: l.set_option(ldap.OPT_X_TLS_NEWCTX,0)
In [6]: l.simple_bind_s("...", "...")
---------------------------------------------------------------------------
SERVER_DOWN Traceback (most recent call last)
<ipython-input-6-a59dae8ba541> in <module>()
----> 1 l.simple_bind_s("...", "...")
/usr/lib64/python2.7/site-packages/ldap/ldapobject.pyc in simple_bind_s(self, who, cred, serverctrls, clientctrls)
205 simple_bind_s([who='' [,cred='']]) -> None
206 """
--> 207 msgid = self.simple_bind(who,cred,serverctrls,clientctrls)
208 resp_type, resp_data, resp_msgid, resp_ctrls = self.result3(msgid,all=1,timeout=self.timeout)
209 return resp_type, resp_data, resp_msgid, resp_ctrls
/usr/lib64/python2.7/site-packages/ldap/ldapobject.pyc in simple_bind(self, who, cred, serverctrls, clientctrls)
199 simple_bind([who='' [,cred='']]) -> int
200 """
--> 201 return self._ldap_call(self._l.simple_bind,who,cred,RequestControlTuples(serverctrls),RequestControlTuples(clientctrls))
202
203 def simple_bind_s(self,who='',cred='',serverctrls=None,clientctrls=None):
/usr/lib64/python2.7/site-packages/ldap/ldapobject.pyc in _ldap_call(self, func, *args, **kwargs)
97 try:
98 try:
---> 99 result = func(*args,**kwargs)
100 if __debug__ and self._trace_level>=2:
101 if func.__name__!="unbind_ext":
SERVER_DOWN: {'info': 'TLS error -8157:Certificate extension not found.', 'desc': "Can't contact LDAP server"}
In [1]: import ldap
In [2]: l = ldap.initialize('ldaps://...:636')
In [3]: l.set_option(ldap.OPT_X_TLS_REQUIRE_CERT,ldap.OPT_X_TLS_ALLOW)
In [4]: l.set_option(ldap.OPT_X_TLS_CACERTFILE,"/etc/pki/ca-trust/source/anchors/cacert.pem")
In [5]: l.protocol_version = ldap.VERSION3
In [6]: l.set_option(ldap.OPT_REFERRALS, 0)
In [7]: l.simple_bind_s("...", "...")
---------------------------------------------------------------------------
SERVER_DOWN Traceback (most recent call last)
<ipython-input-7-a59dae8ba541> in <module>()
----> 1 l.simple_bind_s("...", "...")
/usr/lib64/python2.7/site-packages/ldap/ldapobject.pyc in simple_bind_s(self, who, cred, serverctrls, clientctrls)
205 simple_bind_s([who='' [,cred='']]) -> None
206 """
--> 207 msgid = self.simple_bind(who,cred,serverctrls,clientctrls)
208 resp_type, resp_data, resp_msgid, resp_ctrls = self.result3(msgid,all=1,timeout=self.timeout)
209 return resp_type, resp_data, resp_msgid, resp_ctrls
/usr/lib64/python2.7/site-packages/ldap/ldapobject.pyc in simple_bind(self, who, cred, serverctrls, clientctrls)
199 simple_bind([who='' [,cred='']]) -> int
200 """
--> 201 return self._ldap_call(self._l.simple_bind,who,cred,RequestControlTuples(serverctrls),RequestControlTuples(clientctrls))
202
203 def simple_bind_s(self,who='',cred='',serverctrls=None,clientctrls=None):
/usr/lib64/python2.7/site-packages/ldap/ldapobject.pyc in _ldap_call(self, func, *args, **kwargs)
97 try:
98 try:
---> 99 result = func(*args,**kwargs)
100 if __debug__ and self._trace_level>=2:
101 if func.__name__!="unbind_ext":
SERVER_DOWN: {'info': "TLS error -8172:Peer's certificate issuer has been marked as not trusted by the user.", 'desc': "Can't contact LDAP server"}
import ldap
import os
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_NEVER)
l = ldap.initialize('ldaps://x.x.x.x:636')
l.set_option(ldap.OPT_REFERRALS, 0)
l.set_option(ldap.OPT_PROTOCOL_VERSION, 3)
l.set_option(ldap.OPT_X_TLS_CACERTFILE, os.getcwd()+"/cacert.pem")
l.set_option(ldap.OPT_X_TLS,ldap.OPT_X_TLS_DEMAND)
l.set_option(ldap.OPT_X_TLS_DEMAND, True)
l.set_option(ldap.OPT_DEBUG_LEVEL, 255)
#l.start_tls_s()
在我的机器上,python 2.6;我发现 /etc/openldap/ldap.conf
被使用并优先于一些选项,即使它们设置为 ldap.set_option(..., ...)
.
根据您的发行版,它可能希望证书位于 /etc/openldap/cacerts
而不是 /etc/openldap/certs
这是我调试此类问题的方法。
1。在系统范围内安装证书 (openldap)
cp mycert.pem /etc/openldap/certs
cacertdir_rehash /etc/openldap/certs
2。在系统范围内安装根证书(可选)
如果您将同一个根证书用于其他用途,您可能需要:
update-ca-trust enable
cp mycert.pem /etc/pki/ca-trust/source/anchors/
update-ca-trust extract
update-ca-trust check
3。编辑 /etc/openldap/ldap.conf
编辑配置文件:
# /etc/openldap/ldap.conf
base dc=example,dc=com
uri ldaps://ldap.example.com:636/
ssl yes
tls_cacertdir /etc/openldap/certs
pam_password md5
当 ldapsearch
正常工作时停止。
4。编写测试脚本
例如test_ldap.py
#!/usr/bin/env python
import ldap, sys
LDAP_SERVER = 'ldaps://ldap.example.com:636'
LDAP_BASE = 'dc=example,dc=com'
try:
conn = ldap.initialize(LDAP_SERVER)
except ldap.LDAPError, e:
sys.stderr.write("Fatal Error.n")
raise
# this may or may not raise an error, e.g. TLS error -8172
items = conn.search_s(LDAP_BASE, ldap.SCOPE_SUBTREE, attrlist=['dn'])
5。使用 strace
如果上述步骤失败,您可以使用strace查看具体情况,例如
strace -e open test_ldap.py