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

多Windows域LDAP用户认证异常问题求助

多Windows域LDAP认证证书冲突问题

问题描述

我需要通过LDAP对3个独立Windows域的用户进行认证,每个域有专属DC,证书直接在PHP代码中配置。目前遇到的问题是:Apache重启后,先登录的域用户可正常完成认证,其他域用户登录时,Apache错误日志会出现证书颁发者验证失败的错误;重启Apache后切换至其他域登录,原域用户又无法认证。

关键代码

$certpath=$this->globalparameter->parameters["constants"]["CertifPath"];
switch ($domainname) {
      case "imofa":
        $DC=$this->globalparameter->parameters["constants"]["DcIMF"];
        $certname=$this->globalparameter->parameters["constants"]["CertifIMF"];  
      break;
      case "havexmobility2":
        $upn=str_ireplace("mobility2","mobility",$upn);  //kvůli úpravě DC pro o365 
        $DC=$this->globalparameter->parameters["constants"]["DcHXM"];
        $certname=$this->globalparameter->parameters["constants"]["CertifHXM"]; 
      break;
    default:   // default je "havex2"
        $upn=str_ireplace("havex2","havex",$upn);  //kvůli úpravě DC pro o365 
        $DC=$this->globalparameter->parameters["constants"]["DcHXA"];
        $certname=$this->globalparameter->parameters["constants"]["CertifHXA"];                      
}

ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, 7);  //zapnout debug
ldap_set_option(null, LDAP_OPT_X_TLS_CACERTDIR, $certpath);  
ldap_set_option(null, LDAP_OPT_X_TLS_CACERTFILE, $certpath.'\\'.$certname);                
$s="ldaps://".$DC;
$ds= ldap_connect($s,636);

if ($ds) {
    ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
    ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);
    error_reporting(0); 
    ldap_start_tls($ds);
    $r=ldap_bind ($ds, $upn, $password);
// ... 后续代码
ldap_unbind($ds);

日志示例

正常登录日志

ldap_connect_to_host: TCP DCM1.HAVEXMOBILITY2.CZ:636
ldap_new_socket: 1660
ldap_prepare_socket: 1660
ldap_connect_to_host: Trying 192.168.30.250:636
ldap_pvt_connect: fd: 1660 tm: -1 async: 0
attempting to connect: 
connect success
TLS trace: SSL_connect:before SSL initialization
TLS trace: SSL_connect:SSLv3/TLS write client hello
TLS trace: SSL_connect:SSLv3/TLS write client hello
TLS trace: SSL_connect:SSLv3/TLS read server hello
TLS certificate verification: depth: 1, err: 0, subject: /DC=cz/DC=havexmobility2/CN=havexmobility2-DCM1-CA, issuer: /DC=cz/DC=havexmobility2/CN=havexmobility2-DCM1-CA
TLS certificate verification: depth: 0, err: 0, subject: /CN=DCM1.havexmobility2.cz, issuer: /DC=cz/DC=havexmobility2/CN=havexmobility2-DCM1-CA
TLS trace: SSL_connect:SSLv3/TLS read server certificate
TLS trace: SSL_connect:SSLv3/TLS read server key exchange
TLS trace: SSL_connect:SSLv3/TLS read server certificate request
TLS trace: SSL_connect:SSLv3/TLS read server done

认证失败日志

connect success
TLS trace: SSL_connect:before SSL initialization
TLS trace: SSL_connect:SSLv3/TLS write client hello
TLS trace: SSL_connect:SSLv3/TLS write client hello
TLS trace: SSL_connect:SSLv3/TLS read server hello
TLS certificate verification: depth: 0, err: 20, subject: /CN=DCM1.havexmobility2.cz, issuer: /DC=cz/DC=havexmobility2/CN=havexmobility2-DCM1-CA
TLS certificate verification: Error, unable to get local issuer certificate
TLS trace: SSL3 alert write:fatal:unknown CA
TLS trace: SSL_connect:error in error
TLS: can't connect: error:1416F086:SSL routines:tls_process_server_certificate:certificate verify failed (unable to get local issuer certificate).
ldap_err2string

回答

问题根源在于你使用NULL作为ldap_set_option的第一个参数,这会设置全局LDAP选项。Apache是多进程模型,每个进程的全局LDAP选项会被缓存,第一个请求设置的证书路径会被该进程后续所有请求复用,导致其他域的证书验证失败。

你可以通过以下几种方式解决:

  • 针对单个连接设置TLS选项(推荐)
    不要使用全局选项,而是在ldap_connect成功后,针对当前连接$ds设置TLS相关选项:

    $ds= ldap_connect($s,636);
    if ($ds) {
        // 针对当前连接设置TLS选项
        ldap_set_option($ds, LDAP_OPT_X_TLS_CACERTDIR, $certpath);  
        ldap_set_option($ds, LDAP_OPT_X_TLS_CACERTFILE, $certpath.'\\'.$certname);
        ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
        ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);
        error_reporting(0); 
        ldap_start_tls($ds);
        $r=ldap_bind ($ds, $upn, $password);
        // ... 后续代码
    }
    

    这样每个连接都会使用对应域的证书,不会互相干扰。

  • 合并所有CA证书到单个文件
    将三个域的CA证书合并成一个PEM文件,然后全局设置这个合并后的证书文件。这样不管哪个域的DC证书,都能通过这个合并文件完成验证,无需每次切换证书路径。

  • 重置全局选项(可靠性较低)
    在设置新的证书路径前,先尝试将LDAP_OPT_X_TLS_CACERTFILE设置为空,再设置新路径,但这种方式无法完全规避Apache进程的全局状态缓存问题,不推荐作为主要解决方案。

内容的提问来源于stack exchange,提问作者Petr Domácí

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 20:33:09