C# производительность LDAP

Там, где я работаю, у нас есть два режима аутентификации:

CAS является основным методом, но он часто ненадежен в пиковое время трафика, поэтому мы использовали LDAP в качестве резервного режима, когда замечаем, что CAS не работает. Раньше мы использовали PHP для откатывания LDAP и получили разумную производительность. Во время входа не было заметной задержки, кроме ожидаемого времени задержки сети. Для входа в систему, вероятно, потребовалось ~250-500 мс с использованием LDAP.

Сейчас мы создаем новую систему и выбрали ASP.NET MVC4 в качестве платформы, а не PHP, и мне поручено попытаться заставить этот запасной вариант снова работать. Я потянул свои волосы в течение приблизительно 6 часов теперь, пробуя различные вещи снова и снова, получая тот же самый результат (возможно, я безумен). Наконец-то мне удалось подключиться к LDAP, аутентифицировать пользователя и получить его атрибуты от LDAP. Однако выполнение запроса постоянно занимает 4,5 секунды, независимо от того, какой метод я пробую.

Это очень удивительно для меня, поскольку версия PHP способна сделать почти то же самое в 1/8 раза, и может показаться, что.NET Framework имеет отличную поддержку LDAP/ActiveDirectory. Я делаю что-то невероятно ужасно неправильно?

Вот внутренняя часть моей функции в ее нынешнем виде (это последняя итерация, которой удается выполнить все за один 4,5-секундный запрос):

public Models.CASAttributes Authenticate(string username, string pwd)
{
    string uid = string.Format("uid={0},ou=People,o=byu.edu", username);

    LdapDirectoryIdentifier identifier = new LdapDirectoryIdentifier("ldap.byu.edu", 636, false, false);

    try
    {
        using (LdapConnection connection = new LdapConnection(identifier))
        {
            connection.Credential = new NetworkCredential(uid, pwd);
            connection.AuthType = AuthType.Basic;
            connection.SessionOptions.SecureSocketLayer = true;
            connection.SessionOptions.ProtocolVersion = 3;

            string filter = "(uid=" + username + ")";
            SearchRequest request = new SearchRequest("ou=People,o=byu.edu", filter, SearchScope.Subtree);
            Stopwatch sw = Stopwatch.StartNew();
            SearchResponse response = connection.SendRequest(request) as SearchResponse;
            sw.Stop();
            Debug.WriteLine(sw.ElapsedMilliseconds);
            foreach (SearchResultEntry entry in response.Entries)
            {
                Debug.WriteLine(entry.DistinguishedName);
                foreach (System.Collections.DictionaryEntry attribute in entry.Attributes)
                {
                    Debug.WriteLine(attribute.Key + " " + attribute.Value.GetType().ToString());
                }
                Debug.WriteLine("");
            }
        }
    }
    catch
    {
        Debugger.Break();
    }

    Debugger.Break();
    return null; //debug
}

Версия PHP этого следует за этой последовательностью:

  1. Привязывайте анонимно и ищите информацию о пользователях, используя basedn и cn
  2. Привязать снова, используя имя пользователя и пароль пользователя, чтобы увидеть, являются ли они подлинными

Он выполняет две привязки (соединяет?) В 1/8 от времени, необходимого для выполнения одной версии.NET! Это такая вещь, которая заставляет меня думать, что мне чего-то не хватает.

Я пробовал методы, основанные на следующих сайтах:

РЕДАКТИРОВАТЬ:

Используя wireshark, я увидел, что сделаны следующие запросы:

  1. bindRequest, проходящий по моему uid (delta 0.7ms)
  2. Успех bindResponse (дельта 2 мс)
  3. searchRequest "ou = People, o = byu.edu" wholdSubtree (delta 0.2ms)
  4. searchResEntry "uid =my uid, ou = People, o = byu.edu" | searchResDone успех 1 результат (дельта 10,8мс)
  5. unbindRequest (дельта 55,7 мс)

Очевидно, что накладные расходы поступают от.NET, а не от запросов. Они не добавляют до 4,5 секунд ни в каком виде, форме или форме.

2 ответа

Решение

ldap.byu.edu обязательно выглядит как полное имя хоста DNS. Вам следует изменить конструктор LdapDirectoryIdentifier на new LdapDirectoryIdentifier("ldap.byu.edu", 636, true, false),

Я думаю, что вы определенно на правильном пути, используя System.DirectoryServices для этого, возможно, вам просто нужно немного подправить поисковый запрос.

Вы только хотите получить один результат здесь, правильно? Установите свой размер соответственно:

request.SizeLimit = 1;

Это сложно, но также убедитесь, что вы подавляете реферальные привязки. Вы хотите установить это, прежде чем позвонить connection.SendRequest(request):

//Setting the DomainScope will suppress referral binds from occurring during the search
SearchOptionsControl SuppressReferrals = new SearchOptionsControl(SearchOption.DomainScope);
request.Controls.Add(SuppressReferrals);
Другие вопросы по тегам