C# производительность LDAP
Там, где я работаю, у нас есть два режима аутентификации:
- CAS ( http://www.jasig.org/cas)
- 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 этого следует за этой последовательностью:
- Привязывайте анонимно и ищите информацию о пользователях, используя basedn и cn
- Привязать снова, используя имя пользователя и пароль пользователя, чтобы увидеть, являются ли они подлинными
Он выполняет две привязки (соединяет?) В 1/8 от времени, необходимого для выполнения одной версии.NET! Это такая вещь, которая заставляет меня думать, что мне чего-то не хватает.
Я пробовал методы, основанные на следующих сайтах:
- http://roadha.us/2013/04/ldap-authentication-with-c-sharp/ - Требуется 2 запроса, чтобы сделать то, что я хотел, и это было слишком медленно. Я прошел, вероятно, 6 разных попыток сделать это по-разному (варьируя настройки аутентификации и подключения и т. Д.).
- http://web.byu.edu/docs/ldap-authentication-0 - одна версия PHP, но с небольшим фрагментом о.NET внизу. Мне также нужно было получить профиль, и они не были полностью описательными.
- System.DirectoryServices работает медленно? - Текущая версия
РЕДАКТИРОВАТЬ:
Используя wireshark, я увидел, что сделаны следующие запросы:
- bindRequest, проходящий по моему uid (delta 0.7ms)
- Успех bindResponse (дельта 2 мс)
- searchRequest "ou = People, o = byu.edu" wholdSubtree (delta 0.2ms)
- searchResEntry "uid =my uid, ou = People, o = byu.edu" | searchResDone успех 1 результат (дельта 10,8мс)
- 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);