我设法使用ldap_sasl_bind_s 在 GSSAPI 上执行 LDAP SASL 绑定。有兴趣的可以参考一下。
对于客户端和服务器在 GSSAPI SASL 身份验证期间需要执行的操作的抽象描述,“Kerberos V5 (“GSSAPI”) 简单身份验证和安全层 (SASL) 机制” RFC应该阅读;具体来说,“身份验证协议交换的客户端”部分很有趣,因为它指示了我们需要执行的操作序列,以通过 Kerberos 成功绑定到 LDAP 服务器。
ldap_sasl_bind_s 期望的凭据 - 它们的形式和含义 - 取决于所使用的实际身份验证机制,在我们的例子中是 Kerberos。
在微软 SDK 中,Kerberos 是通过 SSPI 提供的——大致是微软对 GSSAPI 的实现;与我们的特定情况相关的方法是:AcquireCredentialsHandle、InitializeSecurityContext、DecryptMessage、EncryptMessage
基于 Kerberos 的 LDAP SASL 绑定有 3 个阶段。
第一阶段
致电AcquireCredentialsHandle 和InitializeSecurityContext。
重要说明:
- 向
AcquireCredentialsHandle 传递一个指向包含实际凭据(领域、用户名、密码)的SEC_WINNT_AUTH_IDENTITY 结构的指针,如果要使用当前线程的凭据,则传递给NULL
- 目标名称应该是映射到运行 LDAP 服务器的帐户的 SPN
- 调用
InitializeSecurityContext时,必须请求相互认证。
如果所有重要参数均正确 - 有效凭据、有效 SPN、NULL 输入令牌 - InitializeSecurityContext 调用应返回 SEC_I_CONTINUE_NEEDED 并正确填充输出令牌。此输出令牌的内容应放入 BERVAL 结构中,ldap_sasl_bind_s 期望作为客户端凭据。
使用来自InitializeSecurityContext 的输出令牌作为客户端凭据调用ldap_sasl_bind_s。如果所有参数都正确 - 空 DN,GSSAPI 作为机制名称 - 实际调用应该返回 LDAP_SUCCESS 并且 LDAP 会话的最新 LDAP 错误应该是 LDAP_SASL_BIND_IN_PROGRESS。
附带说明一下,可以通过在会话上调用 ldap_get_option 来发现 LDAP 会话的最新 LDAP 错误,并使用 LDAP_OPT_ERROR_NUMBER 作为选项。
第二阶段
在成功调用ldap_sasl_bind_s 后,它的最后一个参数指向一个包含服务器凭据的BERVAL 结构。这个BERVAL 结构的内容现在应该用作第二次调用InitializeSecurityContext 的输入标记。
对InitializeSecurityContext 的第二次调用应该返回SEC_OK 和一个空的输出令牌。
此空输出令牌应用作对ldap_sasl_bind_s 的另一次调用的客户端凭据。对ldap_sasl_bind_s 的第二次调用应返回LDAP_SUCCESS,LDAP 会话的最新LDAP 错误为LDAP_SASL_BIND_IN_PROGRESS。
第三阶段
在第二次成功调用ldap_sasl_bind_s 之后,它的最后一个参数指向一个包含服务器数据的BERVAL 结构。此服务器数据应作为输入提供给DecryptMessage。正如前面提到的 RFC 中规定的,解密后的数据必须是 4 个字节长。
客户端应根据同一 RFC 中的信息构建其回复。
注意:在我的例子中,我省略了 RFC 中提到的授权 ID。据我了解,空的授权 id 会导致身份验证 id 也用于授权。
然后客户端构建的回复应作为输入传递给EncryptMessage。然后应将EncryptMessage 调用的输出作为客户端凭据传递给ldap_sasl_bind_s 的第三次也是最后一次调用。
注意:在 Kerberos 下使用 EncryptMessage 的 MSDN 文档似乎不完整。谷歌的代码搜索应该有助于提供一个工作示例。此外,对于上述流程的工作示例,可以参考 Samba 的源代码。