我成功地使用ldap_sasl_bind_s
执行了一个基于GSSAPI的LDAP SASL绑定。对于那些感兴趣的人,这里有一些指针。
关于客户端和服务器在GSSAPI SASL身份验证期间需要执行的操作的抽象描述,应该阅读“Kerberos V5(“GSSAPI”)简单身份验证和安全层(SASL)机制” RFC;具体来说,“身份验证协议交换的客户端部分” 部分很重要,因为它给出了我们需要执行的行动序列,以成功地绑定到使用Kerberos的LDAP服务器。
ldap_sasl_bind_s
所期望的凭据的形式和意义取决于实际使用的认证机制,而在我们的情况下是Kerberos。
在Microsoft SDK中,Kerberos通过SSPI可用,这大致上是GSSAPI的Microsoft实现;与我们特定情况相关的方法是:AcquireCredentialsHandle
,InitializeSecurityContext
,DecryptMessage
,EncryptMessage
基于Kerberos的LDAP SASL绑定有3个阶段。
第一阶段
调用AcquireCredentialsHandle
和InitializeSecurityContext
。
这里有一些重要的注意事项:
- 将指向包含实际凭据(域名、用户名、密码)的
SEC_WINNT_AUTH_IDENTITY
结构体的指针传递给AcquireCredentialsHandle
,或者如果要使用当前线程的凭据,则传递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_OPT_ERROR_NUMBER
作为选项来发现最近的LDAP错误。
第二阶段:
成功调用
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文档似乎不完整。Google的Code Search可以协助查找工作示例。此外,可查阅Samba源代码以获得上述流程的工作示例。