Использование StartTLS с LDAP из System.DirectoryServices - PullRequest
1 голос
/ 18 января 2012

Я пытаюсь подключиться к серверу LDAP, который требует StartTLS, но безуспешно - всякий раз, когда я использую либо SessionOptions.StartTransportLayerSecurity (..), либо для SessionOptions.SecureSocketLayer, равную true, я получаю исключения.1002 * Вот код, который я использую:

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?

Ответы [ 3 ]

3 голосов
/ 26 января 2012

Раньше было довольно много незначительных несовместимостей стека LDAP, которые все еще могли бы применяться к потенциально устаревшему сценарию, который может использовать ваш клиент.

Ниже перечислены наиболее часто встречающиеся проблемы, связанные с несовместимостью.между OpenLDAP и стеком LDAP от Microsoft (я исправлю и / или заменю эти ссылки, как только появится больше информации) :

Очевидно, что обновление либо OpenLDAP и / или Windows (в идеале обаконечно) должны исправить эти проблемы, если они окажутся виновником здесь.

Удачи!

2 голосов
/ 26 января 2012

После небольшой работы над этой проблемой я обнаружил, что столкнулся с парой проблем:

  1. В коде была ошибка, из-за которой номер порта неправильно изменялся на порт SSL (636) при подключении к AD в нашем тестовом наборе (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).

Спасибо Штеффену за то, что он указал мне направление версий OpenLDAP, которое привело меня к этому решению.

2 голосов
/ 24 января 2012

Пожалуйста, прочитайте эту тему: Привязка через зашифрованное соединение TLS / SSL

Пример 19. Привязка к экземпляру ADAM на защищенном порту 50001 с использованием обычной аутентификации и 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);
}

И в следующем примере показано «Как использовать 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);
...