Mac M1下Python ldap3连接LDAP服务器证书验证失败排查
问题背景
在Mac M1设备上,使用Python结合ldap3库连接LDAP服务器时,提取服务器证书并配置后仍出现证书验证失败错误。相关代码、操作步骤及错误信息如下:
代码实现
from ldap3 import Server, Connection, SUBTREE, ALL, Tls, MODIFY_REPLACE from fastapi import FastAPI from typing import Union from pydantic import BaseModel import ssl app = FastAPI() tls_configuration = Tls(validate=ssl.CERT_REQUIRED,version=ssl.PROTOCOL_TLSv1_2,ca_certs_file="./app/client_cert.pem") server = Server("ldaps://ldaps.adserver.com",port=636,use_ssl=True,tls=tls_configuration, get_info=ALL) conn = Connection(server, user='mydomain.com\\user', password='DemoPass%',auto_bind=True,authentication="NTLM") print(f"Connection: {conn}")
证书提取操作
通过以下命令获取证书,并将---Begin Certificate---到---End Certificate---的内容保存为./app/client_cert.pem:
openssl s_client -connect ldaps.adserver.com:636
错误信息
Traceback (most recent call last): File "/Users/demo/Documents/GitHub/project/app/main.py", line 13, in <module> conn = Connection(server, user='domain\\user', password='DemoPass%',auto_bind=True,authentication="NTLM") ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/demo/anaconda3/lib/python3.11/site-packages/ldap3/core/connection.py", line 363, in __init__ self._do_auto_bind() File "/Users/demo/anaconda3/lib/python3.11/site-packages/ldap3/core/connection.py", line 387, in _do_auto_bind self.open(read_server_info=False) File "/Users/demo/anaconda3/lib/python3.11/site-packages/ldap3/strategy/sync.py", line 57, in open BaseStrategy.open(self, reset_usage, read_server_info) File "/Users/demo/anaconda3/lib/python3.11/site-packages/ldap3/strategy/base.py", line 146, in open raise exception_history[0][0] ldap3.core.exceptions.LDAPSocketOpenError: ("('socket ssl wrapping error: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1006)',)",)
解决方案
一、验证PEM证书文件的有效性
1. 检查证书格式与内容
执行以下命令查看证书详细信息,确认文件是否为有效的X.509证书:
openssl x509 -in ./app/client_cert.pem -text -noout
- 若正常输出证书颁发者、有效期、主题等信息,说明格式正确;
- 若报错(如
unable to load certificate),说明证书内容提取不完整或格式错误,需重新提取。
2. 验证证书链完整性
执行以下命令,用你的PEM文件验证与LDAP服务器的SSL连接:
openssl s_client -connect ldaps.adserver.com:636 -CAfile ./app/client_cert.pem
查看输出末尾的Verify return code:
- 若为
0 (ok),说明证书链完整有效; - 若仍提示
unable to get local issuer certificate,说明仅提取了服务器证书,缺少中间CA或根CA证书,需将完整证书链追加到PEM文件中。
注意:
openssl s_client输出会包含服务器返回的完整证书链(服务器证书、中间CA、根CA),需将所有---Begin Certificate---到---End Certificate---的段落复制到同一个PEM文件,顺序为:服务器证书在前,中间CA次之,根CA最后。
二、在ldap3中正确配置证书
1. 确保证书路径正确
避免相对路径查找失败,建议使用绝对路径指定证书文件:
ca_cert_path = "/Users/demo/Documents/GitHub/project/app/complete_ca_chain.pem" # 替换为你的实际绝对路径
2. 修正TLS配置
调整TLS参数,确保与服务器TLS版本兼容,同时开启主机名验证(生产环境建议保留):
tls_configuration = Tls( validate=ssl.CERT_REQUIRED, version=ssl.PROTOCOL_TLSv1_2, # 若服务器支持TLSv1.3,可改为ssl.PROTOCOL_TLSv1_3 ca_certs_file=ca_cert_path, check_hostname=True )
3. 调整用户名格式
NTLM认证对用户名格式可能有要求,可尝试两种格式:
- 域\用户名:
mydomain.com\\user(注意双反斜杠转义) - UPN格式:
user@mydomain.com
4. 修正后的完整代码
from ldap3 import Server, Connection, SUBTREE, ALL, Tls, MODIFY_REPLACE from fastapi import FastAPI from typing import Union from pydantic import BaseModel import ssl app = FastAPI() # 使用绝对路径指定完整证书链文件 ca_cert_path = "/Users/demo/Documents/GitHub/project/app/complete_ca_chain.pem" tls_configuration = Tls( validate=ssl.CERT_REQUIRED, version=ssl.PROTOCOL_TLSv1_2, ca_certs_file=ca_cert_path, check_hostname=True ) # Server地址可省略ldaps://前缀,已通过use_ssl=True启用SSL server = Server("ldaps.adserver.com", port=636, use_ssl=True, tls=tls_configuration, get_info=ALL) # 尝试UPN格式用户名 conn = Connection(server, user='user@mydomain.com', password='DemoPass%', auto_bind=True, authentication="NTLM") print(f"Connection: {conn}")
5. Mac M1特殊注意事项
若使用Anaconda环境的Python,可能存在SSL库与系统的兼容性问题:
- 可安装
certifi库,尝试使用系统信任的CA证书:
代码中指定:pip install certifi
但如果是企业内部私有CA,仍需使用自己的完整证书链文件。import certifi tls_configuration = Tls( validate=ssl.CERT_REQUIRED, version=ssl.PROTOCOL_TLSv1_2, ca_certs_file=certifi.where(), check_hostname=True )
内容的提问来源于stack exchange,提问作者K P
相关产品推荐
相关产品推荐

