1

我正在尝试连接到需要 StartTLS 的 LDAP 服务器,但没有运气 - 每当我使用 SessionOptions.StartTransportLayerSecurity(..) 或将 SessionOptions.SecureSocketLayer 设置为 true 时,都会出现异常。

这是我正在使用的代码:

using (var connection = new LdapConnection(new LdapDirectoryIdentifier(config.LdapServer, config.Port, false, false)))
{
    connection.SessionOptions.ProtocolVersion = 3;
    connection.Credential = new NetworkCredential(config.BindDN, config.BindPassword);
    connection.SessionOptions.VerifyServerCertificate += (conn, cert) => {return true;};
    connection.AuthType = AuthType.Basic;
    //connection.SessionOptions.SecureSocketLayer = true;
    connection.SessionOptions.StartTransportLayerSecurity(null); // throws here, same if done after bind.
    connection.Bind();

    ... do stuff with connection
}

产生的异常是“TlsOperationException:发生未指定的错误”,它在调用 StartTransportLayerSecurity 方法时发生。

我已经针对 OpenLDAP 服务器和 Active Directory 测试了代码,但两者都不起作用。

有谁知道如何让 StartTLS 与 System.DirectoryServices 一起工作?

4

3 回答 3

3

过去存在大量微妙的 LDAP 堆栈不兼容问题,这仍然适用于您的客户可能正在使用的潜在遗留场景。

以下是有关 OpenLDAP 和 Microsoft 的 LDAP 堆栈之间不兼容的最常见问题(一旦有更多信息可用,我将修改和/或替换这些链接)

显然,更新 OpenLDAP 和/或 Windows(当然最好同时更新)应该可以解决这些问题,如果它们被证明是这里的罪魁祸首。

祝你好运!

于 2012-01-26T15:15:49.513 回答
2

请阅读本主题: 通过 TLS/SSL 加密连接绑定

示例 19. 使用基本身份验证和 SSL/TLS 绑定到安全端口 50001 上的 ADAM 实例

string hostNameAndSSLPort = "sea-dc-02.fabrikam.com:50001";
string userName = "cn=User1,cn=AdamUsers,cn=ap1,dc=fabrikam,dc=com";
string password = "adamPassword01!";

// establish a connection
LdapConnection connection = new LdapConnection(hostNameAndSSLPort);

// create an LdapSessionOptions object to configure session 
// settings on the connection.
LdapSessionOptions options = connection.SessionOptions;

options.ProtocolVersion = 3;

options.SecureSocketLayer = true;

connection.AuthType = AuthType.Basic;

NetworkCredential credential =
        new NetworkCredential(userName, password);

connection.Credential = credential;

try
{
    connection.Bind();
    Console.WriteLine("\nUser account {0} validated using " +
        "ssl.", userName);

    if (options.SecureSocketLayer == true)
    {
        Console.WriteLine("SSL for encryption is enabled\nSSL information:\n" +
        "\tcipher strength: {0}\n" +
        "\texchange strength: {1}\n" +
        "\tprotocol: {2}\n" +
        "\thash strength: {3}\n" +
        "\talgorithm: {4}\n",
        options.SslInformation.CipherStrength,
        options.SslInformation.ExchangeStrength,
        options.SslInformation.Protocol,
        options.SslInformation.HashStrength,
        options.SslInformation.AlgorithmIdentifier);
    }

}
catch (LdapException e)
{
    Console.WriteLine("\nCredential validation for User " +
        "account {0} using ssl failed\n" +
        "LdapException: {1}", userName, e.Message);
}
catch (DirectoryOperationException e)
{
    Console.WriteLine("\nCredential validation for User " +
    "account {0} using ssl failed\n" +
    "DirectoryOperationException: {1}", userName, e.Message);
}

下一个示例显示“如何使用 TLS 进行身份验证和执行任务”

string hostOrDomainName = "fabrikam.com";
string userName = "user1";
string password = "password1";

// establish a connection to the directory
LdapConnection connection = new LdapConnection(hostOrDomainName);

NetworkCredential credential =
    new NetworkCredential(userName, password, domainName);

connection.Credential = credential;

connection.AuthType = AuthType.Basic;

LdapSessionOptions options = connection.SessionOptions;

options.ProtocolVersion = 3;

try
{
    options.StartTransportLayerSecurity(null);
    Console.WriteLine("TLS started.\n");
}
catch (Exception e)
{
    Console.WriteLine("Start TLS failed with {0}", 
        e.Message);
    return;
}

try
{
    connection.Bind();
    Console.WriteLine("Bind succeeded using basic " +
        "authentication and SSL.\n");

    Console.WriteLine("Complete another task over " +
        "this SSL connection");
    TestTask(hostName);
}
catch (LdapException e)
{
    Console.WriteLine(e.Message);
}

try
{
    options.StopTransportLayerSecurity();
    Console.WriteLine("Stop TLS succeeded\n");
}
catch (Exception e)
{
    Console.WriteLine("Stop TLS failed with {0}", e.Message);
}

 Console.WriteLine("Switching to negotiate auth type");
 connection.AuthType = AuthType.Negotiate;

 Console.WriteLine("\nRe-binding to the directory");
 connection.Bind();

// complete some action over this non-SSL connection
// note, because Negotiate was used, the bind request 
// is secure. 
// run a task using this new binding
TestTask(hostName);
于 2012-01-24T08:43:05.520 回答
2

在这个问题上做了更多的工作后,我发现我遇到了几个问题:

  1. 在我们的测试套件中连接到 AD 时,代码中有一个错误,端口号被错误地更改为 SSL 端口 (636)(doh!)。
  2. OpenLDAP 测试服务器(它是我们客户的副本)使用的是 openldap-2.4.18 - StartTLS 存在已知问题。

在将补丁应用到 OpenLDAP 之后(如此处所述 - http://www.openldap.org/lists/openldap-bugs/200405/msg00096.html)我们能够修复#2 - 此时我们开始遇到不同的错误“发生本地错误”。

虽然最初我们有这个代码:

connection.SessionOptions.VerifyServerCertificate 
    += (conn, cert) => {return true;};

我们在测试时删除了它,并且因为 OpenLDAP 服务器使用的是自签名证书,所以它不在受信任的存储中。重新引入该回调解决了此问题,尽管我们现在将其设为可配置选项,即“验证服务器证书 Y/N”,因此客户需要选择跳过检查(主要供我们的 QA 团队使用)。

感谢 Steffen 为我指明了 OpenLDAP 版本的方向,这使我找到了这个解决方案。

于 2012-01-26T10:24:39.757 回答