将 StartTLS 与 System.DirectoryServices 中的 LDAP 结合使用

发布于 2024-12-27 08:35:19 字数 1022 浏览 0 评论 0原文

我正在尝试连接到需要 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 一起使用?

I'm trying to connect to an LDAP server which requires StartTLS, but having no luck - whenever I use either the SessionOptions.StartTransportLayerSecurity(..) or set SessionOptions.SecureSocketLayer to true, I get exceptions.

Here's the code I'm using:

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
}

The resulting exception is "TlsOperationException: An unspecified error occurred", which happens when invoking the StartTransportLayerSecurity method.

I've tested the code against both and OpenLDAP server and Active Directory, but neither works.

Does anyone know how to get StartTLS working with System.DirectoryServices?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

oО清风挽发oО 2025-01-03 08:35:19

请阅读本主题:
通过 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);

Please read this topic:
Binding over a TLS/SSL Encrypted Connection

Example 19. Binding to an ADAM instance on secure port 50001 using Basic authentication and SSL/TLS

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);
}

And the next example show "How to use TLS to authenticate and perform a task"

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);
追我者格杀勿论 2025-01-03 08:35:19

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

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

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

祝你好运!

There used to be a fair amount of subtle LDAP stack incompatibilities in the wild, which could still apply to the potentially legacy scenario your customer might be using.

The following are the most commonly encountered issues regarding incompatibilities between OpenLDAP and Microsoft's LDAP stack (I'll amend and/or replace these links once more info is available):

Obviously, updating either OpenLDAP and/or Windows (ideally both of course) should remedy these issues, if they turn out to be the culprit here.

Good luck!

看春风乍起 2025-01-03 08:35:19

在对这个问题进行更多工作后,我发现我遇到了几个问题:

  1. 代码中存在一个错误,在我们的测试中连接到 AD 时,端口号被错误地更改为 SSL 端口 (636)套房(哦!)。
  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 服务器使用自签名证书,所以它不在受信任的存储中。重新引入该回调解决了这个问题,尽管我们现在将其设置为可配置选项,即“验证服务器证书是/否”,因此客户需要选择跳过检查(主要供我们的 QA 团队使用)。

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

After a bit more work on this issue I found that I was running up against a couple of issues:

  1. There was a bug in the code where the port number was being incorrectly changed to the SSL port (636) when connecting to AD in our test suite (doh!).
  2. The OpenLDAP test server (that was a replica of our customers) was using openldap-2.4.18 - which has known issues with StartTLS.

After applying a patch to OpenLDAP (as discussed here - http://www.openldap.org/lists/openldap-bugs/200405/msg00096.html) we were able to fix #2 - at which point we started getting a different error "A local error occurred".

Though originally we had this code:

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

We had removed it while testing, and because the OpenLDAP server was using a self-signed cert, that was not in a trusted store. Re-introducing that callback resolved this issue, though we now make it a configurable option i.e. "Verify Server Certificate Y/N" so customers need to opt into skipping the check (mostly for our QA team to use).

Thanks Steffen for pointing me in the direction of OpenLDAP versions which lead me to this solution.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文