Как проверить creds Active Directory через LDAP + SSL?
Я пытаюсь использовать .NET 3.5 System.DirectoryServices.AccountManagement
пространство имен для проверки учетных данных пользователя на нашем сервере LDAP Active Directory через SSL зашифрованное соединение LDAP. Вот пример кода:
using (var pc = new PrincipalContext(ContextType.Domain, "sd.example.com:389", "DC=sd,DC=example,DC=com", ContextOptions.Negotiate))
{
return pc.ValidateCredentials(_username, _password);
}
этот код отлично работает над незащищенным LDAP (порт 389), однако я бы предпочел не передавать комбинацию user/pass в ясном тексте. Но когда я перехожу на LDAP + SSL (порт 636), я получаю следующее исключение:
System.DirectoryServices.Protocols.DirectoryOperationException: The server cannot handle directory requests.
at System.DirectoryServices.Protocols.ErrorChecking.CheckAndSetLdapError(Int32 error)
at System.DirectoryServices.Protocols.LdapSessionOptions.FastConcurrentBind()
at System.DirectoryServices.AccountManagement.CredentialValidator.BindLdap(NetworkCredential creds, ContextOptions contextOptions)
at System.DirectoryServices.AccountManagement.CredentialValidator.Validate(String userName, String password)
at System.DirectoryServices.AccountManagement.PrincipalContext.ValidateCredentials(String userName, String password)
at (my code)
порт 636 работает для других действия, такие как поиск непарольной информации для этой записи LDAP/AD...
UserPrincipal.FindByIdentity(pc, IdentityType.SamAccountName, _username)
...поэтому я знаю, что это не настройка SSL моего сервера LDAP, так как он работает через SSL для других запросов.
кто-нибудь получил ValidateCredentials(...)
вызов для работы по SSL? Можете объяснить как? Или есть другой / лучший способ безопасной проверки учетных данных AD/LDAP?
4 ответов
я смог проверить учетные данные, используя System.DirectoryServices.Protocols
пространство имен, благодаря коллеге. Вот код:
// See http://support.microsoft.com/kb/218185 for full list of LDAP error codes
const int ldapErrorInvalidCredentials = 0x31;
const string server = "sd.example.com:636";
const string domain = "sd.example.com";
try
{
using (var ldapConnection = new LdapConnection(server))
{
var networkCredential = new NetworkCredential(_username, _password, domain);
ldapConnection.SessionOptions.SecureSocketLayer = true;
ldapConnection.AuthType = AuthType.Negotiate;
ldapConnection.Bind(networkCredential);
}
// If the bind succeeds, the credentials are valid
return true;
}
catch (LdapException ldapException)
{
// Invalid credentials throw an exception with a specific error code
if (ldapException.ErrorCode.Equals(ldapErrorInvalidCredentials))
{
return false;
}
throw;
}
Я не в восторге от использования блока try / catch для управления логикой принятия решений, но это то, что работает. :/
может быть, это другой путь. В проверке полномочий нет ничего необычного. ContextOptions должны быть установлены правильно.
значение по умолчанию:
ContextOptions.Переговоры | ContextOptions.Подписание | ContextOptions.Запечатывание
Добавить Ssl:
ContextOptions.Переговоры | ContextOptions.Подписание | ContextOptions.Уплотнение | ContextOptions.SecureSocketLayer
ContextOptions.Вести переговоров или ContextOptions.Требуется SimpleBind. Или независимо от того, что ваш сервер должен выполнить аутентификацию. ContextOptions поддерживает только бит или бит.
можно попробовать также установить ContextOptions напрямую этот способ В способ ValidateCredentials.
using (var pc = new PrincipalContext(ContextType.Domain, "sd.example.com:636", "DC=sd,DC=example,DC=com", ContextOptions.Negotiate | ContextOptions.SecureSocketLayer))
{
return pc.ValidateCredentials(_username, _password);
}
или
using (var pc = new PrincipalContext(ContextType.Domain, "sd.example.com:636", "DC=sd,DC=example,DC=com", ContextOptions.Negotiate))
{
return pc.ValidateCredentials(_username, _password, ContextOptions.Negotiate | ContextOptions.SecureSocketLayer);
}
для меня, метод ValidateCredentials работает просто отлично. Проблема, как я обнаружил, была на сервере, на котором размещалось объявление (я использую AD LDS). Необходимо связать сертификат сервера с экземпляром AD. Поэтому, если ваш экземпляр назывался "MyAD" (или ActiveDirectoryWebService), вам нужно было открыть MMC, щелкнуть в модуле "сертификаты", выбрать "учетная запись службы", а затем выбрать "MyAD" из списка. Оттуда вы можете добавить сертификат SSL в личный магазин "MyAD". Этот наконец, запустил обработку SSL.
подозреваю, из того, что я знаю о LdapConnection способ и тот факт, что вы опустили функцию обратного вызова, что вы не проверять сертификат сервера. Это грязная работа и ValidateCredentials это бесплатно. Возможно, ничего особенного, но все же дыра в системе безопасности.
Я знаю, что это старо, но для любого, кто снова столкнется с этим:
PrincipalContext.ValidateCredentials(...)
по умолчанию пытается открыть SSL-соединение (ldap_init(NULL, 636)
) с последующей установкой опции LDAP_OPT_FAST_CONCURRENT_BIND
.
если a (доверенный?) клиентский сертификат присутствует, однако соединение LDAP неявно связано, и быстрая привязка больше не может быть включена. PrincipalContext не рассмотреть это дело и выдает неожиданный DirectoryOperationException
.
решение: Для поддержки SSL, где это возможно, но есть запасной, вызова ValidateCredentials(...)
с параметрами по умолчанию (т. е. без вариантов). Если это не удается с DirectoryOperationException
, повторить задание ContextOptions
(переговоры / печать / подписание), который является то, что ValidateCredentials
внутренне делает для ожидаемого LdapException
в любом случае.