php_ldap - 尝试 StartTLS 但在失败时继续

php_ldap - Try StartTLS but keep going when it fails

由于不同的客户环境 运行 相同的代码,我正在尝试使用 PHP 构建一个 LDAP 身份验证系统,它可以在 3 种模式下工作:

  1. 根本不使用 StartTLS(当 LDAP 服务器更喜欢 LDAPS 时)
  2. 尝试 StartTLS,但如果 LDAP 服务器拒绝 TLS,则继续不安全
  3. 如果 LDAP 服务器拒绝 TLS,请尝试启动 TLS 并中止身份验证

这里是代码的简化版本:

// ldap_connect is successful and returns $ldap

ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldap, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_NEVER); // I tried ALLOW and TRY as well and got the same results

// $configStartTls contains 1, 2 or 3 (see options above)
if ($configStartTls > 1) {
    $tlsOk = ldap_start_tls($ldap) || ($configStartTls === 2);
} else {
    $tlsOk = true;
}
if ($tlsOk) {
    // ldap_bind here
}

以下是不支持 TLS 的 LDAP 服务器的结果(ldap_start_tls 总是 returns 错误),对于 $configStartTls

的每个值
  1. ldap_bind 成功 - OK
  2. ldap_bind 失败 - KO
  3. ldap_bind 未尝试 - OK

案例2:

我不明白为什么 ldap_bind 在情况 2 中失败。就好像使用 ldap_start_tls 强制使用 TLS 一样。我希望在失败后能够以不安全的方式继续与 LDAP 服务器通信。

我是否必须在失败后取消使用 StartTLS 才能实施选项 2?我该怎么做?

我只需要再次执行 ldap_connect 即可在不使用 StartTLS 的情况下重新开始。我曾尝试过但失败了,但这只是因为我忘记在 ldap_connectldap_bind 之间重新应用 LDAP 选项,这意味着我可能在第二次尝试时使用了 LDAP v2,这就是为什么服务器拒绝了。

这是完整的工作代码。它包括不支持 TLS 的 free public LDAP server 的 URI、BindDN 和密码,因此任何遇到相同问题的人都可以自己尝试代码并修改它。只需将 $startTlsMode 的值更改为任何常量即可尝试其他模式。

const TLS_NO = 1;
const TLS_OPTIONAL = 2;
const TLS_MANDATORY = 3;

$startTlsMode = TLS_OPTIONAL;

$ldap = connectAndSetOptions();
if ($startTlsMode === TLS_OPTIONAL || $startTlsMode === TLS_MANDATORY) {
    $tlsOk = ldap_start_tls($ldap);
} else {
    $tlsOk = true;
}

// TLS optional and StartTLS failed, start over without using StartTLS
if ($startTlsMode === TLS_OPTIONAL && !$tlsOk) {
    $ldap = connectAndSetOptions();
    $tlsOk = true;
}

// TLS successful or not necessary, proceed with binding
if ($tlsOk) {
    $bindOK = ldap_bind($ldap, 'cn=read-only-admin,dc=example,dc=com', 'password');
    echo $bindOK ? 'Bind successful' : 'Bind failed';
} else {
    echo 'No bind attempt';
}

function connectAndSetOptions() {
    $ldap = ldap_connect('ldap://ldap.forumsys.com:389');
    ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
    ldap_set_option($ldap, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_TRY);
    return $ldap;
}