You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
    
    代码中指定:
    import certifi
    tls_configuration = Tls(
        validate=ssl.CERT_REQUIRED,
        version=ssl.PROTOCOL_TLSv1_2,
        ca_certs_file=certifi.where(),
        check_hostname=True
    )
    
    但如果是企业内部私有CA,仍需使用自己的完整证书链文件。

内容的提问来源于stack exchange,提问作者K P

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 18:58:25